Commit 0fda78e4 by Performance System

1

parent 4c5265c1
Pipeline #3260 failed with stage
in 2 minutes 9 seconds
# ========================================
# 绩效计分系统 - 生产环境配置
# ========================================
# ==================== 前端配置 ====================
# API 服务地址 - 生产环境使用相对路径,通过Nginx代理
# 前端和后端在同一域名下,通过Nginx代理/api路径到后端
VITE_API_BASE_URL=
# ==================== 后端配置 ====================
# 数据库配置
# 格式: postgresql://用户名:密码@主机:端口/数据库名
DATABASE_URL=postgresql://performance_user:performance_pass@postgres:5432/performance_db
# API 服务配置
API_HOST=0.0.0.0
API_PORT=8000
# CORS 配置(生产环境允许所有来源,因为通过Nginx代理)
CORS_ORIGINS=*
# 安全配置
# 生产环境请务必更改为强密码
SECRET_KEY=your-production-secret-key-change-this
# JWT配置
JWT_SECRET_KEY=your-production-jwt-secret-key-change-this
JWT_ALGORITHM=HS256
JWT_EXPIRE_HOURS=24
# 日志配置
LOG_LEVEL=INFO
LOG_FILE=logs/api.log
# 数据迁移配置
MIGRATION_BATCH_SIZE=100
...@@ -56,7 +56,8 @@ services: ...@@ -56,7 +56,8 @@ services:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
args: args:
VITE_API_BASE_URL: ${VITE_API_BASE_URL} # 生产环境使用空字符串,让前端使用相对路径通过Nginx代理
VITE_API_BASE_URL: ""
container_name: performance_frontend container_name: performance_frontend
ports: ports:
- "4001:80" - "4001:80"
......
...@@ -15,16 +15,28 @@ server { ...@@ -15,16 +15,28 @@ server {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
# CORS 头部 # 超时设置(处理大文件上传)
add_header Access-Control-Allow-Origin *; proxy_connect_timeout 60s;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; proxy_send_timeout 60s;
add_header Access-Control-Allow-Headers "Content-Type, Authorization"; proxy_read_timeout 60s;
# 请求体大小限制(允许上传大图片)
client_max_body_size 10M;
# CORS 头部(后端已处理CORS,这里作为备份)
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
add_header Access-Control-Allow-Credentials "true" always;
# 处理 OPTIONS 预检请求 # 处理 OPTIONS 预检请求
if ($request_method = 'OPTIONS') { if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization"; add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
add_header Access-Control-Allow-Credentials "true" always;
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204; return 204;
} }
} }
......
...@@ -74,8 +74,10 @@ router.beforeEach(async (to, from, next) => { ...@@ -74,8 +74,10 @@ router.beforeEach(async (to, from, next) => {
return return
} }
// 检查角色权限 // 检查角色权限 - 使用 effectiveUser 而不是 currentUser
if (to.meta.roles && !to.meta.roles.includes(authStore.currentUser.role)) { // 这样管理员切换到用户视图时,会使用 viewAsUser 的角色
const effectiveRole = authStore.effectiveUser?.role || authStore.currentUser?.role
if (to.meta.roles && !to.meta.roles.includes(effectiveRole)) {
// 权限不足,跳转到用户面板 // 权限不足,跳转到用户面板
next('/user') next('/user')
return return
...@@ -84,7 +86,10 @@ router.beforeEach(async (to, from, next) => { ...@@ -84,7 +86,10 @@ router.beforeEach(async (to, from, next) => {
// 已登录用户访问登录页,直接跳转到对应面板 // 已登录用户访问登录页,直接跳转到对应面板
if (to.path === '/login' && authStore.isAuthenticated) { if (to.path === '/login' && authStore.isAuthenticated) {
if (authStore.currentUser.role === 'admin') { // 如果正在查看用户视图,跳转到用户面板
if (authStore.isViewingAsUser) {
next('/user')
} else if (authStore.currentUser.role === 'admin') {
next('/admin') next('/admin')
} else { } else {
next('/user') next('/user')
......
...@@ -4,8 +4,12 @@ ...@@ -4,8 +4,12 @@
* 替换原有的 localStorage 存储机制 * 替换原有的 localStorage 存储机制
*/ */
// API 基础配置 - 直接使用后端API地址 // API 基础配置
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000' // 生产环境:VITE_API_BASE_URL 为空字符串,使用相对路径通过Nginx代理
// 开发环境:VITE_API_BASE_URL 为 http://localhost:8000,直接访问后端
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL !== undefined
? import.meta.env.VITE_API_BASE_URL
: 'http://localhost:8000'
/** /**
* HTTP 请求封装类 * HTTP 请求封装类
......
...@@ -97,6 +97,10 @@ export const useAuthStore = defineStore('auth', () => { ...@@ -97,6 +97,10 @@ export const useAuthStore = defineStore('auth', () => {
currentUser.value = null currentUser.value = null
localStorage.removeItem('currentUser') localStorage.removeItem('currentUser')
// 清除用户视图状态
viewAsUser.value = null
localStorage.removeItem('viewAsUser')
// 清除tokens // 清除tokens
apiClient.clearTokens() apiClient.clearTokens()
......
...@@ -10,6 +10,14 @@ ...@@ -10,6 +10,14 @@
<p class="period-info">当前统计周期:{{ currentPeriod }}</p> <p class="period-info">当前统计周期:{{ currentPeriod }}</p>
</div> </div>
<div class="header-actions"> <div class="header-actions">
<!-- 如果是管理员查看用户视图,显示返回按钮 -->
<el-button
v-if="authStore.isViewingAsUser"
type="primary"
@click="handleSwitchBackToAdmin"
>
返回管理员视图
</el-button>
<el-button @click="handleLogout">退出登录</el-button> <el-button @click="handleLogout">退出登录</el-button>
</div> </div>
</div> </div>
...@@ -750,6 +758,15 @@ const refreshData = async () => { ...@@ -750,6 +758,15 @@ const refreshData = async () => {
/** /**
* 返回管理员视图
*/
const handleSwitchBackToAdmin = () => {
authStore.switchBackToAdmin()
router.push('/admin')
ElMessage.success('已返回管理员视图')
}
/**
* 退出登录 * 退出登录
*/ */
const handleLogout = async () => { const handleLogout = async () => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment