chore(version): update version to 1.2.2 - dynamic api
This commit is contained in:
@@ -12,6 +12,8 @@ export default defineConfig({
|
|||||||
request: {},
|
request: {},
|
||||||
locale: {
|
locale: {
|
||||||
default: 'vi-VN',
|
default: 'vi-VN',
|
||||||
|
// baseNavigator: false,
|
||||||
|
// antd: true,
|
||||||
},
|
},
|
||||||
favicons: ['/logo.png'],
|
favicons: ['/logo.png'],
|
||||||
layout: {
|
layout: {
|
||||||
|
|||||||
39
DYNAMIC_API_CONFIG.md
Normal file
39
DYNAMIC_API_CONFIG.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Cấu hình API động theo IP thiết bị
|
||||||
|
|
||||||
|
## Cách hoạt động
|
||||||
|
|
||||||
|
1. **ApiConfigService** tự động detect IP từ `window.location.hostname`
|
||||||
|
2. **Request interceptor** tự động thêm base URL vào mọi request
|
||||||
|
3. Không cần cấu hình proxy phức tạp nữa
|
||||||
|
|
||||||
|
## Cách deploy trên nhiều thiết bị
|
||||||
|
|
||||||
|
### 1. Build ứng dụng
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Deploy lên từng thiết bị
|
||||||
|
|
||||||
|
- Copy folder `dist` lên thiết bị
|
||||||
|
- Serve static files (nginx, apache, hoặc simple HTTP server)
|
||||||
|
|
||||||
|
### 3. Truy cập từ thiết bị
|
||||||
|
|
||||||
|
- Nếu thiết bị có IP `192.168.1.100`, truy cập: `http://192.168.1.100`
|
||||||
|
- Ứng dụng sẽ tự động gọi API đến `http://192.168.1.100:81`
|
||||||
|
|
||||||
|
## Ví dụ các thiết bị
|
||||||
|
|
||||||
|
| Thiết bị | IP | URL truy cập | API endpoint |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| Device 1 | 192.168.1.100 | http://192.168.1.100 | http://192.168.1.100:81/api/* |
|
||||||
|
| Device 2 | 192.168.1.101 | http://192.168.1.101 | http://192.168.1.101:81/api/* |
|
||||||
|
| Device 3 | 10.0.0.50 | http://10.0.0.50 | http://10.0.0.50:81/api/* |
|
||||||
|
|
||||||
|
## Lưu ý
|
||||||
|
|
||||||
|
- Backend API cần chạy trên port 81 của mỗi thiết bị
|
||||||
|
- Đảm bảo CORS được cấu hình đúng trên backend
|
||||||
|
- Nếu dùng domain, cần cấu hình HTTPS tương ứng
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { ROUTE_LOGIN } from '@/constants';
|
import { ROUTE_LOGIN } from '@/constants';
|
||||||
|
import { apiConfig } from '@/services/ApiConfigService';
|
||||||
import { getToken, removeToken } from '@/utils/localStorageUtils';
|
import { getToken, removeToken } from '@/utils/localStorageUtils';
|
||||||
import { history, RequestConfig } from '@umijs/max';
|
import { history, RequestConfig } from '@umijs/max';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
@@ -84,9 +85,18 @@ export const handleRequestConfig: RequestConfig = {
|
|||||||
// Request interceptors
|
// Request interceptors
|
||||||
requestInterceptors: [
|
requestInterceptors: [
|
||||||
(url: string, options: any) => {
|
(url: string, options: any) => {
|
||||||
|
console.log('URL Request:', url, options);
|
||||||
|
|
||||||
|
// Nếu URL không phải absolute URL, thêm base URL
|
||||||
|
let finalUrl = url;
|
||||||
|
if (!url.startsWith('http')) {
|
||||||
|
const baseUrl = apiConfig.getApiBaseUrl();
|
||||||
|
finalUrl = `${baseUrl}${url}`;
|
||||||
|
}
|
||||||
|
|
||||||
const token = getToken();
|
const token = getToken();
|
||||||
return {
|
return {
|
||||||
url,
|
url: finalUrl,
|
||||||
options: {
|
options: {
|
||||||
...options,
|
...options,
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -1,24 +1,59 @@
|
|||||||
const proxy: Record<string, any> = {
|
// Hàm lấy IP từ hostname hiện tại (chỉ hoạt động runtime)
|
||||||
dev: {
|
const getCurrentIP = () => {
|
||||||
'/api': {
|
if (typeof window !== 'undefined') {
|
||||||
target: 'http://192.168.30.103:81',
|
const hostname = window.location.hostname;
|
||||||
changeOrigin: true,
|
// Nếu là localhost hoặc IP local, trả về IP mặc định
|
||||||
},
|
if (
|
||||||
},
|
hostname === 'localhost' ||
|
||||||
test: {
|
hostname.startsWith('192.168.') ||
|
||||||
'/test': {
|
hostname.startsWith('10.')
|
||||||
target: 'https://test-sgw-device.gms.vn',
|
) {
|
||||||
changeOrigin: true,
|
console.log('Host name: ', hostname);
|
||||||
secure: false,
|
|
||||||
},
|
return hostname;
|
||||||
},
|
}
|
||||||
prod: {
|
// Nếu là domain, có thể cần map sang IP tương ứng
|
||||||
'/test': {
|
return hostname;
|
||||||
target: 'https://prod-sgw-device.gms.vn',
|
}
|
||||||
changeOrigin: true,
|
return process.env.REACT_APP_API_HOST || '192.168.30.102'; // fallback từ env
|
||||||
secure: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Hàm tạo proxy config động
|
||||||
|
const createDynamicProxy = () => {
|
||||||
|
const currentIP = getCurrentIP();
|
||||||
|
const isLocalIP =
|
||||||
|
currentIP.startsWith('192.168.') ||
|
||||||
|
currentIP.startsWith('10.') ||
|
||||||
|
currentIP === 'localhost';
|
||||||
|
|
||||||
|
return {
|
||||||
|
dev: {
|
||||||
|
'/api': {
|
||||||
|
target: `http://${currentIP}:81`,
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
'/test': {
|
||||||
|
target: isLocalIP
|
||||||
|
? `http://${currentIP}:81`
|
||||||
|
: 'https://test-sgw-device.gms.vn',
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: !isLocalIP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
prod: {
|
||||||
|
'/test': {
|
||||||
|
target: isLocalIP
|
||||||
|
? `http://${currentIP}:81`
|
||||||
|
: 'https://prod-sgw-device.gms.vn',
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: !isLocalIP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const proxy: Record<string, any> = createDynamicProxy();
|
||||||
|
|
||||||
export default proxy;
|
export default proxy;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const Footer = () => {
|
|||||||
background: 'none',
|
background: 'none',
|
||||||
color: 'white',
|
color: 'white',
|
||||||
}}
|
}}
|
||||||
copyright="2025 Sản phẩm của Mobifone v1.2.1"
|
copyright="2025 Sản phẩm của Mobifone v1.2.2"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
54
src/services/ApiConfigService.ts
Normal file
54
src/services/ApiConfigService.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// Service để quản lý API endpoint động
|
||||||
|
class ApiConfigService {
|
||||||
|
private static instance: ApiConfigService;
|
||||||
|
private currentIP: string = '';
|
||||||
|
|
||||||
|
private constructor() {}
|
||||||
|
|
||||||
|
static getInstance(): ApiConfigService {
|
||||||
|
if (!ApiConfigService.instance) {
|
||||||
|
ApiConfigService.instance = new ApiConfigService();
|
||||||
|
}
|
||||||
|
return ApiConfigService.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lấy IP từ URL hiện tại
|
||||||
|
getCurrentIP(): string {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const hostname = window.location.hostname;
|
||||||
|
// Nếu là localhost hoặc IP local
|
||||||
|
if (
|
||||||
|
hostname === 'localhost' ||
|
||||||
|
hostname.startsWith('192.168.') ||
|
||||||
|
hostname.startsWith('10.')
|
||||||
|
) {
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
|
// Nếu là domain, trả về hostname
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
|
return '192.168.30.102'; // fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lấy base URL cho API calls
|
||||||
|
getApiBaseUrl(): string {
|
||||||
|
const ip = this.getCurrentIP();
|
||||||
|
const isLocal =
|
||||||
|
ip.startsWith('192.168.') || ip.startsWith('10.') || ip === 'localhost';
|
||||||
|
|
||||||
|
if (isLocal) {
|
||||||
|
return `http://${ip}:81`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nếu là domain, có thể cần HTTPS
|
||||||
|
return `https://${ip}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lấy full API URL
|
||||||
|
getApiUrl(endpoint: string): string {
|
||||||
|
const baseUrl = this.getApiBaseUrl();
|
||||||
|
return `${baseUrl}${endpoint}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const apiConfig = ApiConfigService.getInstance();
|
||||||
Reference in New Issue
Block a user