فهرست منبع

第二次提交

wyn 5 ماه پیش
والد
کامیت
bcfb449cd5
8فایلهای تغییر یافته به همراه90 افزوده شده و 29 حذف شده
  1. 17 0
      .env
  2. 1 1
      index.html
  3. 2 1
      src/Dashboard.tsx
  4. 28 0
      src/config/env.ts
  5. 5 1
      src/main.tsx
  6. 3 2
      src/utils/axios.ts
  7. 24 19
      src/views/Login.tsx
  8. 10 5
      vite.config.ts

+ 17 - 0
.env

@@ -0,0 +1,17 @@
+# 标题
+VITE_APP_TITLE=能量隔离系统
+
+# 项目本地运行端口号
+VITE_PORT=80
+# 请求路径
+VITE_BASE_URL='http://120.27.232.27:48080'
+# open 运行 npm run dev 时自动打开浏览器
+VITE_OPEN=true
+
+# 租户开关
+VITE_APP_TENANT_ENABLE=true
+
+# 默认账户密码
+VITE_APP_DEFAULT_LOGIN_TENANT = 博士安全
+VITE_APP_DEFAULT_LOGIN_USERNAME = admin
+VITE_APP_DEFAULT_LOGIN_PASSWORD = admin123

+ 1 - 1
index.html

@@ -4,7 +4,7 @@
     <head>
       <meta charset="UTF-8" />
       <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-      <title>企业SaaS登录页面设计</title>
+      <title>能量隔离系统</title>
     </head>
 
     <body>

+ 2 - 1
src/Dashboard.tsx

@@ -11,6 +11,7 @@ import ProfileSettings from './components/ProfileSettings';
 import CockpitDashboard from './components/CockpitDashboard';
 import { authApi } from './api';
 import { toast } from 'sonner';
+import { env } from './config/env';
 
 export default function Dashboard() {
   const navigate = useNavigate();
@@ -97,7 +98,7 @@ export default function Dashboard() {
                   <div className="absolute -top-0.5 -right-0.5 w-3 h-3 bg-green-400 rounded-full border-2 border-white"></div>
                 </div>
                 <div>
-                  <h1 className="text-lg text-gray-900">{t('login.title')}</h1>
+                  <h1 className="text-lg text-gray-900">{env.appTitle}</h1>
                   <p className="text-xs text-gray-500">{t('login.subtitle')}</p>
                 </div>
               </div>

+ 28 - 0
src/config/env.ts

@@ -0,0 +1,28 @@
+// 环境变量配置
+export const env = {
+  // 应用标题
+  appTitle: import.meta.env.VITE_APP_TITLE || '能量隔离系统',
+  
+  // API 基础URL
+  baseUrl: import.meta.env.VITE_BASE_URL || 'http://localhost:8080',
+  
+  // 租户功能是否启用
+  tenantEnable: import.meta.env.VITE_APP_TENANT_ENABLE === 'true' || false,
+  
+  // 默认登录信息
+  defaultLogin: {
+    tenant: import.meta.env.VITE_APP_DEFAULT_LOGIN_TENANT?.trim() || '博士安全',
+    username: import.meta.env.VITE_APP_DEFAULT_LOGIN_USERNAME?.trim() || 'admin',
+    password: import.meta.env.VITE_APP_DEFAULT_LOGIN_PASSWORD?.trim() || 'admin123',
+  },
+  
+  // 开发服务器端口
+  port: import.meta.env.VITE_PORT || 3000,
+  
+  // 是否自动打开浏览器
+  open: import.meta.env.VITE_OPEN === 'true' || false,
+} as const;
+
+// 导出类型
+export type EnvConfig = typeof env;
+

+ 5 - 1
src/main.tsx

@@ -2,8 +2,12 @@ import { createRoot } from "react-dom/client";
 import { RouterProvider } from "react-router-dom";
 import { router } from "./routes";
 import "./config/i18n"; // 初始化 i18n
+import { env } from "./config/env";
 import "./index.css";
 
+// 设置页面标题
+document.title = env.appTitle;
+
 createRoot(document.getElementById("root")!).render(
   <RouterProvider router={router} />
-);
+);

+ 3 - 2
src/utils/axios.ts

@@ -1,9 +1,10 @@
 import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
 import { toast } from 'sonner';
+import { env } from '../config/env';
 
 // 创建 axios 实例
 const axiosInstance: AxiosInstance = axios.create({
-  baseURL: import.meta.env.VITE_API_BASE_URL || '/api',
+  baseURL: env.baseUrl ? `${env.baseUrl}/api` : '/api',
   timeout: 30000, // 30秒超时
   headers: {
     'Content-Type': 'application/json',
@@ -12,7 +13,7 @@ const axiosInstance: AxiosInstance = axios.create({
 
 // 请求拦截器
 axiosInstance.interceptors.request.use(
-  (config: AxiosRequestConfig) => {
+  (config) => {
     // 从 localStorage 获取 token
     const token = localStorage.getItem('token');
     if (token && config.headers) {

+ 24 - 19
src/views/Login.tsx

@@ -4,13 +4,14 @@ import { useTranslation } from 'react-i18next';
 import { Shield, Zap, Lock, User, Eye, EyeOff, ArrowRight, Activity, Radio, Layers, Building2, Globe } from 'lucide-react';
 import { authApi } from '../api';
 import { toast } from 'sonner';
+import { env } from '../config/env';
 
 export default function Login() {
   const navigate = useNavigate();
   const { t, i18n } = useTranslation();
-  const [tenant, setTenant] = useState('博士安全');
-  const [username, setUsername] = useState('admin');
-  const [password, setPassword] = useState('123');
+  const [tenant, setTenant] = useState(env.defaultLogin.tenant);
+  const [username, setUsername] = useState(env.defaultLogin.username);
+  const [password, setPassword] = useState(env.defaultLogin.password);
   const [showPassword, setShowPassword] = useState(false);
   const [rememberMe, setRememberMe] = useState(false);
   const [isLoading, setIsLoading] = useState(false);
@@ -80,12 +81,14 @@ export default function Login() {
     setIsLoading(true);
     
     try {
-      const response = await authApi.login({ tenant, username, password });
+      // 如果未启用租户功能,使用默认租户
+      const loginTenant = env.tenantEnable ? tenant : env.defaultLogin.tenant;
+      const response = await authApi.login({ tenant: loginTenant, username, password });
       
       // 保存 token 和租户信息
       if (response.token) {
         localStorage.setItem('token', response.token);
-        localStorage.setItem('tenant', tenant);
+        localStorage.setItem('tenant', loginTenant);
         
         if (rememberMe) {
           localStorage.setItem('rememberMe', 'true');
@@ -239,7 +242,7 @@ export default function Login() {
                 </div>
               </div>
               <div>
-                <h1 className="text-2xl text-gray-900">{t('login.title')}</h1>
+                <h1 className="text-2xl text-gray-900">{env.appTitle}</h1>
                 <p className="text-xs text-blue-600 tracking-widest mt-0.5">{t('login.subtitle')}</p>
               </div>
             </div>
@@ -349,21 +352,23 @@ export default function Login() {
                 </div>
 
                 <form onSubmit={handleSubmit} className="space-y-5">
-                  <div>
-                    <div className="relative">
-                      <div className="absolute left-4 top-1/2 -translate-y-1/2 text-gray-400">
-                        <Building2 className="w-5 h-5" />
+                  {env.tenantEnable && (
+                    <div>
+                      <div className="relative">
+                        <div className="absolute left-4 top-1/2 -translate-y-1/2 text-gray-400">
+                          <Building2 className="w-5 h-5" />
+                        </div>
+                        <input
+                          type="text"
+                          placeholder={t('login.tenant')}
+                          value={tenant}
+                          onChange={(e) => setTenant(e.target.value)}
+                          className="w-full h-13 pl-12 pr-4 bg-white border-2 border-gray-200 rounded-xl outline-none focus:border-blue-400 focus:ring-4 focus:ring-blue-100 transition-all"
+                          required
+                        />
                       </div>
-                      <input
-                        type="text"
-                        placeholder={t('login.tenant')}
-                        value={tenant}
-                        onChange={(e) => setTenant(e.target.value)}
-                        className="w-full h-13 pl-12 pr-4 bg-white border-2 border-gray-200 rounded-xl outline-none focus:border-blue-400 focus:ring-4 focus:ring-blue-100 transition-all"
-                        required
-                      />
                     </div>
-                  </div>
+                  )}
 
                   <div>
                     <label className="block text-sm text-gray-700 mb-2 ml-1">

+ 10 - 5
vite.config.ts

@@ -1,10 +1,14 @@
 
-  import { defineConfig } from 'vite';
+  import { defineConfig, loadEnv } from 'vite';
   import react from '@vitejs/plugin-react-swc';
   import path from 'path';
 
-  export default defineConfig({
-    plugins: [react()],
+  export default defineConfig(({ mode }) => {
+    // 加载环境变量
+    const env = loadEnv(mode, process.cwd(), '');
+    
+    return {
+      plugins: [react()],
     resolve: {
       extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
       alias: {
@@ -54,7 +58,8 @@
       outDir: 'build',
     },
     server: {
-      port: 3000,
-      open: true,
+      port: Number(env.VITE_PORT) || 3000,
+      open: env.VITE_OPEN === 'true' || false,
     },
+    };
   });