fix: 优化生产环境前端端口显示逻辑
- 检测是否为生产环境(通过检查dist目录) - 生产环境显示Nginx配置提示,不自动重启 - 开发环境保持自动重启功能 - 区分显示生产环境和开发环境状态
This commit is contained in:
+1
-1
@@ -135,7 +135,7 @@ MYSQL_DATABASE=idc_management
|
|||||||
#### 2. 安装生产依赖
|
#### 2. 安装生产依赖
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install --only=production
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 3. 配置数据库
|
#### 3. 配置数据库
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
require('dotenv').config();
|
||||||
|
const { sequelize } = require('../db');
|
||||||
|
|
||||||
|
async function migrate() {
|
||||||
|
try {
|
||||||
|
console.log('开始 MySQL 数据库迁移...');
|
||||||
|
console.log('数据库类型:', process.env.DB_TYPE);
|
||||||
|
|
||||||
|
// 检查列是否存在(MySQL 方式)
|
||||||
|
const [columns] = await sequelize.query(`
|
||||||
|
SELECT COLUMN_NAME
|
||||||
|
FROM INFORMATION_SCHEMA.COLUMNS
|
||||||
|
WHERE TABLE_NAME = 'deviceFields'
|
||||||
|
AND COLUMN_NAME = 'isSystem'
|
||||||
|
AND TABLE_SCHEMA = '${process.env.MYSQL_DATABASE || 'it_assest'}'
|
||||||
|
`);
|
||||||
|
|
||||||
|
if (columns.length === 0) {
|
||||||
|
// 添加 isSystem 列
|
||||||
|
await sequelize.query(`
|
||||||
|
ALTER TABLE deviceFields
|
||||||
|
ADD COLUMN isSystem BOOLEAN DEFAULT 0
|
||||||
|
COMMENT '是否为系统字段,系统字段不可删除'
|
||||||
|
`);
|
||||||
|
console.log('✓ isSystem 列添加成功');
|
||||||
|
} else {
|
||||||
|
console.log('✓ isSystem 列已存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新系统字段标记
|
||||||
|
const systemFields = [
|
||||||
|
'deviceId', 'name', 'type', 'model', 'serialNumber',
|
||||||
|
'rackId', 'position', 'height', 'powerConsumption',
|
||||||
|
'status', 'purchaseDate', 'warrantyExpiry'
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const fieldName of systemFields) {
|
||||||
|
await sequelize.query(`
|
||||||
|
UPDATE deviceFields SET isSystem = 1 WHERE fieldName = '${fieldName}'
|
||||||
|
`);
|
||||||
|
console.log(`✓ 标记系统字段: ${fieldName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证结果
|
||||||
|
const [results] = await sequelize.query(`
|
||||||
|
SELECT fieldName, displayName, isSystem
|
||||||
|
FROM deviceFields
|
||||||
|
ORDER BY isSystem DESC, fieldName
|
||||||
|
`);
|
||||||
|
|
||||||
|
console.log('\n========== 迁移结果 ==========');
|
||||||
|
console.log('字段总数:', results.length);
|
||||||
|
console.log('系统字段数:', results.filter(r => r.isSystem).length);
|
||||||
|
console.log('\n系统字段列表:');
|
||||||
|
results.filter(r => r.isSystem).forEach(r => {
|
||||||
|
console.log(` 🔒 ${r.displayName} (${r.fieldName})`);
|
||||||
|
});
|
||||||
|
console.log('\n可选字段列表:');
|
||||||
|
results.filter(r => !r.isSystem).forEach(r => {
|
||||||
|
console.log(` ✏️ ${r.displayName} (${r.fieldName})`);
|
||||||
|
});
|
||||||
|
console.log('==============================\n');
|
||||||
|
|
||||||
|
console.log('✅ 迁移完成!');
|
||||||
|
process.exit(0);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ 迁移失败:', error.message);
|
||||||
|
console.error(error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
migrate();
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
const { sequelize } = require('../db');
|
||||||
|
|
||||||
|
async function migrate() {
|
||||||
|
try {
|
||||||
|
console.log('开始 SQLite 数据库迁移...');
|
||||||
|
|
||||||
|
// 检查列是否存在(SQLite 使用 PRAGMA)
|
||||||
|
const tableInfo = await sequelize.query(
|
||||||
|
"PRAGMA table_info(deviceFields)",
|
||||||
|
{ type: sequelize.QueryTypes.SELECT }
|
||||||
|
);
|
||||||
|
|
||||||
|
const hasIsSystemColumn = tableInfo.some(col => col.name === 'isSystem');
|
||||||
|
|
||||||
|
if (!hasIsSystemColumn) {
|
||||||
|
// 添加 isSystem 列
|
||||||
|
await sequelize.query(
|
||||||
|
"ALTER TABLE deviceFields ADD COLUMN isSystem BOOLEAN DEFAULT 0",
|
||||||
|
{ type: sequelize.QueryTypes.RAW }
|
||||||
|
);
|
||||||
|
console.log('isSystem 列添加成功');
|
||||||
|
} else {
|
||||||
|
console.log('isSystem 列已存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新系统字段标记
|
||||||
|
const systemFields = [
|
||||||
|
'deviceId', 'name', 'type', 'model', 'serialNumber',
|
||||||
|
'rackId', 'position', 'height', 'powerConsumption',
|
||||||
|
'status', 'purchaseDate', 'warrantyExpiry'
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const fieldName of systemFields) {
|
||||||
|
await sequelize.query(
|
||||||
|
`UPDATE deviceFields SET isSystem = 1 WHERE fieldName = '${fieldName}'`,
|
||||||
|
{ type: sequelize.QueryTypes.RAW }
|
||||||
|
);
|
||||||
|
console.log(`标记系统字段: ${fieldName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('迁移完成!');
|
||||||
|
process.exit(0);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('迁移失败:', error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
migrate();
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
15988
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
3000
|
||||||
@@ -71,13 +71,43 @@ const SystemSettings = () => {
|
|||||||
|
|
||||||
await axios.put('/api/system-settings', { settings: updates });
|
await axios.put('/api/system-settings', { settings: updates });
|
||||||
|
|
||||||
// 如果修改了前端端口,同步配置并自动重启
|
// 如果修改了前端端口,同步配置并自动重启(仅开发环境)
|
||||||
if ('frontend_port' in updates) {
|
if ('frontend_port' in updates) {
|
||||||
try {
|
try {
|
||||||
// 1. 同步端口到配置文件
|
// 1. 同步端口到配置文件
|
||||||
await axios.post('/api/system-settings/frontend/port/sync');
|
await axios.post('/api/system-settings/frontend/port/sync');
|
||||||
|
|
||||||
// 2. 显示确认对话框
|
// 2. 检查是否为生产环境
|
||||||
|
const statusRes = await axios.get('/api/system-settings/frontend/status');
|
||||||
|
const isProduction = statusRes.data.isProduction;
|
||||||
|
|
||||||
|
if (isProduction) {
|
||||||
|
// 生产环境:只显示提示,不自动重启
|
||||||
|
Modal.info({
|
||||||
|
title: '前端端口已修改(生产环境)',
|
||||||
|
content: (
|
||||||
|
<div>
|
||||||
|
<p>前端端口已从 <strong>{settings.frontend_port?.value}</strong> 更改为 <strong>{updates.frontend_port}</strong></p>
|
||||||
|
<Alert
|
||||||
|
message="请手动更新服务器配置"
|
||||||
|
description={
|
||||||
|
<div>
|
||||||
|
<p>生产环境由 Nginx 或其他服务器托管,请手动更新服务器配置文件:</p>
|
||||||
|
<p>1. 更新 Nginx 配置中的监听端口</p>
|
||||||
|
<p>2. 重启 Nginx 服务</p>
|
||||||
|
<p>3. 更新 vite.config.js 中的端口配置(用于下次构建)</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
type="info"
|
||||||
|
showIcon
|
||||||
|
style={{ marginTop: 16 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
okText: '知道了'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 开发环境:显示确认对话框并自动重启
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: '前端端口已修改',
|
title: '前端端口已修改',
|
||||||
icon: <ExclamationCircleOutlined />,
|
icon: <ExclamationCircleOutlined />,
|
||||||
@@ -136,6 +166,7 @@ const SystemSettings = () => {
|
|||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
} catch (syncError) {
|
} catch (syncError) {
|
||||||
console.warn('同步前端端口配置失败:', syncError);
|
console.warn('同步前端端口配置失败:', syncError);
|
||||||
message.warning('端口配置已保存,但同步到配置文件失败');
|
message.warning('端口配置已保存,但同步到配置文件失败');
|
||||||
@@ -314,12 +345,15 @@ const SystemSettings = () => {
|
|||||||
<Card title="全局配置" bordered={false}>
|
<Card title="全局配置" bordered={false}>
|
||||||
{frontendStatus && (
|
{frontendStatus && (
|
||||||
<Alert
|
<Alert
|
||||||
message="前端服务状态"
|
message={frontendStatus.isProduction ? "前端服务状态(生产环境)" : "前端服务状态(开发环境)"}
|
||||||
description={
|
description={
|
||||||
<div>
|
<div>
|
||||||
<p>当前端口:<strong>{frontendStatus.port}</strong></p>
|
<p>当前端口:<strong>{frontendStatus.port}</strong></p>
|
||||||
<p>运行状态:{frontendStatus.isRunning ? <Tag color="success">运行中</Tag> : <Tag color="error">未运行</Tag>}</p>
|
<p>运行状态:{frontendStatus.isRunning ? <Tag color="success">运行中</Tag> : <Tag color="error">未运行</Tag>}</p>
|
||||||
{frontendStatus.portInUse && <p style={{ color: '#ff4d4f' }}>警告:端口被其他程序占用</p>}
|
{frontendStatus.portInUse && <p style={{ color: '#ff4d4f' }}>警告:端口被其他程序占用</p>}
|
||||||
|
{frontendStatus.isProduction && (
|
||||||
|
<p style={{ color: '#1890ff' }}>提示:生产环境由 Nginx 或其他服务器托管,如需修改端口请更新服务器配置</p>
|
||||||
|
)}
|
||||||
<p>访问地址:<a href={frontendStatus.url} target="_blank" rel="noopener noreferrer">{frontendStatus.url}</a></p>
|
<p>访问地址:<a href={frontendStatus.url} target="_blank" rel="noopener noreferrer">{frontendStatus.url}</a></p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,12 +169,22 @@ const getStatus = async () => {
|
|||||||
// 检查端口实际占用情况
|
// 检查端口实际占用情况
|
||||||
const portAvailable = await checkPort(port);
|
const portAvailable = await checkPort(port);
|
||||||
|
|
||||||
|
// 检测是否为生产环境(通过检查是否存在 dist 目录)
|
||||||
|
const frontendDir = path.join(__dirname, '../frontend');
|
||||||
|
const distDir = path.join(frontendDir, 'dist');
|
||||||
|
const isProduction = fs.existsSync(distDir);
|
||||||
|
|
||||||
|
// 生产环境:只要端口被占用就认为服务在运行(Nginx/其他服务器)
|
||||||
|
// 开发环境:通过 PID 判断
|
||||||
|
const isServiceRunning = isProduction ? !portAvailable : isRunning;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pid,
|
pid,
|
||||||
port,
|
port,
|
||||||
isRunning,
|
isRunning: isServiceRunning,
|
||||||
portInUse: !portAvailable && !isRunning, // 端口被占用但服务未运行
|
portInUse: !portAvailable && !isServiceRunning, // 端口被占用但服务未运行
|
||||||
url: `http://localhost:${port}`
|
url: `http://localhost:${port}`,
|
||||||
|
isProduction // 是否为生产环境
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user