feat: migrate ERP configuration from .env to per-user database storage

- Moved ERP credentials (URL, username, password) from environment variables to dbo_BIPUsers table
- Each user now has their own ERP configuration stored in the database
- Added UserErpConfigService for managing per-user ERP settings
- Updated cleaner and extractor handlers to fetch ERP config from database instead of .env
- Removed ERP fields from ConfigManager UI editable fields
- Added new IPC handlers and preload APIs for user ERP config management
- Includes migration script to transfer existing .env ERP settings to database
- Added migration guide documentation

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Misaka
2026-03-05 21:52:54 +08:00
parent 3d2127b660
commit 5977254180
15 changed files with 1654 additions and 53 deletions

View File

@@ -28,7 +28,11 @@ export const BIP_USERS_CONFIG = {
USER_TYPE: 'UserType',
PASSWORD: 'Password',
COMPUTER_NAME: 'ComputerName',
CREATE_TIME: 'CreateTime'
CREATE_TIME: 'CreateTime',
// ERP Configuration columns
ERP_URL: 'ERP_URL',
ERP_USERNAME: 'ERP_Username',
ERP_PASSWORD: 'ERP_Password'
}
} as const
@@ -480,6 +484,162 @@ export class BIPUsersDAO {
}
}
/**
* Get ERP configuration for a user
* @param username - The username to get ERP config for
* @returns ERP configuration object or null if not found
*/
async getUserErpConfig(username: string): Promise<{
url: string
username: string
password: string
} | null> {
try {
const dbService = await this.getDatabaseService()
const tableName = this.getTableName()
const cols = BIP_USERS_CONFIG.COLUMNS
if (this.dbType === 'sqlserver') {
const sqlString = `
SELECT ${cols.ERP_URL}, ${cols.ERP_USERNAME}, ${cols.ERP_PASSWORD}
FROM ${tableName}
WHERE UserName = @username
`
const result = await (dbService as SqlServerService).queryWithParams(sqlString, {
username: { value: username, type: sql.NVarChar(255) }
})
if (result.rows.length > 0) {
const row = result.rows[0]
return {
url: (row[cols.ERP_URL] as string) || '',
username: (row[cols.ERP_USERNAME] as string) || '',
password: (row[cols.ERP_PASSWORD] as string) || ''
}
}
return null
} else {
const sqlString = `
SELECT ${cols.ERP_URL}, ${cols.ERP_USERNAME}, ${cols.ERP_PASSWORD}
FROM ${tableName}
WHERE UserName = ?
`
const result = await (dbService as MySqlService).query(sqlString, [username])
if (result.rows.length > 0) {
const row = result.rows[0]
return {
url: (row[cols.ERP_URL] as string) || '',
username: (row[cols.ERP_USERNAME] as string) || '',
password: (row[cols.ERP_PASSWORD] as string) || ''
}
}
return null
}
} catch (error) {
console.error('[BIPUsersDAO] Get user ERP config error:', error)
return null
}
}
/**
* Update ERP configuration for a user
* @param username - The username to update ERP config for
* @param erpUrl - The ERP URL
* @param erpUsername - The ERP username
* @param erpPassword - The ERP password
* @returns True if successful
*/
async updateUserErpConfig(
username: string,
erpUrl: string,
erpUsername: string,
erpPassword: string
): Promise<boolean> {
try {
const dbService = await this.getDatabaseService()
const tableName = this.getTableName()
const cols = BIP_USERS_CONFIG.COLUMNS
if (this.dbType === 'sqlserver') {
const sqlString = `
UPDATE ${tableName}
SET ${cols.ERP_URL} = @erpUrl,
${cols.ERP_USERNAME} = @erpUsername,
${cols.ERP_PASSWORD} = @erpPassword
WHERE UserName = @username
`
await (dbService as SqlServerService).queryWithParams(sqlString, {
username: { value: username, type: sql.NVarChar(255) },
erpUrl: { value: erpUrl, type: sql.NVarChar(500) },
erpUsername: { value: erpUsername, type: sql.NVarChar(255) },
erpPassword: { value: erpPassword, type: sql.NVarChar(255) }
})
return true
} else {
const sqlString = `
UPDATE ${tableName}
SET ${cols.ERP_URL} = ?,
${cols.ERP_USERNAME} = ?,
${cols.ERP_PASSWORD} = ?
WHERE UserName = ?
`
await (dbService as MySqlService).query(sqlString, [
erpUrl,
erpUsername,
erpPassword,
username
])
return true
}
} catch (error) {
console.error('[BIPUsersDAO] Update user ERP config error:', error)
return false
}
}
/**
* Get ERP configuration for all users (for migration/audit purposes)
* @returns List of users with their ERP configurations
*/
async getAllUsersErpConfig(): Promise<
Array<{
username: string
erpUrl: string
erpUsername: string
}>
> {
try {
const dbService = await this.getDatabaseService()
const tableName = this.getTableName()
const cols = BIP_USERS_CONFIG.COLUMNS
const sqlString = `
SELECT ${cols.USERNAME}, ${cols.ERP_URL}, ${cols.ERP_USERNAME}
FROM ${tableName}
ORDER BY ${cols.USERNAME}
`
const result =
this.dbType === 'sqlserver'
? await (dbService as SqlServerService).query(sqlString)
: await (dbService as MySqlService).query(sqlString)
return result.rows.map((row) => ({
username: row[cols.USERNAME] as string,
erpUrl: (row[cols.ERP_URL] as string) || '',
erpUsername: (row[cols.ERP_USERNAME] as string) || ''
}))
} catch (error) {
console.error('[BIPUsersDAO] Get all users ERP config error:', error)
return []
}
}
/**
* Disconnect from database
*/

View File

@@ -0,0 +1,316 @@
/**
* Migration Script: Add ERP parameters to BIPUsers table
*
* This script adds ERP_URL, ERP_Username, and ERP_Password columns
* to the dbo_BIPUsers table and initializes all existing users
* with the same ERP credentials from the current .env configuration.
*
* Usage:
* npx tsx src/main/services/user/migration/add-erp-params-migration.ts
*/
import * as fs from 'fs'
import * as path from 'path'
import { fileURLToPath } from 'url'
import { dirname } from 'path'
import { ConfigManager } from '../../config/config-manager'
import { MySqlService } from '../../database/mysql'
import { SqlServerService } from '../../database/sql-server'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
/**
* Migration configuration
*/
const MIGRATION_CONFIG = {
sqlFile: path.join(__dirname, 'add-erp-params-to-bipusers.sql'),
tableName: {
mysql: 'dbo_BIPUsers',
sqlserver: '[dbo].[BIPUsers]'
},
columns: ['ERP_URL', 'ERP_Username', 'ERP_Password']
}
/**
* Check if column exists in MySQL table
*/
async function checkColumnExistsMySQL(
mysqlService: MySqlService,
tableName: string,
columnName: string
): Promise<boolean> {
const sql = `
SELECT COUNT(*) as count
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = ?
AND COLUMN_NAME = ?
`
const result = await mysqlService.query(sql, [tableName, columnName])
return result.rows.length > 0 && (result.rows[0].count as number) > 0
}
/**
* Check if column exists in SQL Server table
*/
async function checkColumnExistsSqlServer(
sqlServerService: SqlServerService,
tableName: string,
columnName: string
): Promise<boolean> {
const sql = `
SELECT COUNT(*) as count
FROM sys.columns
WHERE object_id = OBJECT_ID(${tableName})
AND name = @columnName
`
const result = await sqlServerService.queryWithParams(sql, {
columnName: { value: columnName.replace('ERP_', ''), type: require('mssql').NVarChar(128) }
})
return result.rows.length > 0 && (result.rows[0].count as number) > 0
}
/**
* Add column to MySQL table
*/
async function addColumnMySQL(
mysqlService: MySqlService,
tableName: string,
columnName: string,
columnType: string
): Promise<void> {
const sql = `ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${columnType} NULL`
await mysqlService.query(sql)
console.log(` ✓ Added column ${columnName} to ${tableName}`)
}
/**
* Add column to SQL Server table
*/
async function addColumnSqlServer(
sqlServerService: SqlServerService,
tableName: string,
columnName: string,
columnType: string
): Promise<void> {
const sql = `ALTER TABLE ${tableName} ADD ${columnName} ${columnType} NULL`
await sqlServerService.query(sql)
console.log(` ✓ Added column ${columnName} to ${tableName}`)
}
/**
* Update all users with ERP credentials from .env
*/
async function initializeErpCredentialsMySQL(
mysqlService: MySqlService,
erpUrl: string,
erpUsername: string,
erpPassword: string
): Promise<number> {
const sql = `
UPDATE ${MIGRATION_CONFIG.tableName.mysql}
SET ERP_URL = ?, ERP_Username = ?, ERP_Password = ?
WHERE ERP_URL IS NULL OR ERP_URL = ''
`
const result = await mysqlService.query(sql, [erpUrl, erpUsername, erpPassword])
return result.rowCount
}
/**
* Update all users with ERP credentials from .env (SQL Server)
*/
async function initializeErpCredentialsSqlServer(
sqlServerService: SqlServerService,
erpUrl: string,
erpUsername: string,
erpPassword: string
): Promise<number> {
const sql = `
UPDATE ${MIGRATION_CONFIG.tableName.sqlserver}
SET ERP_URL = @erpUrl, ERP_Username = @erpUsername, ERP_Password = @erpPassword
WHERE ERP_URL IS NULL OR ERP_URL = ''
`
const result = await sqlServerService.queryWithParams(sql, {
erpUrl: { value: erpUrl, type: require('mssql').NVarChar(500) },
erpUsername: { value: erpUsername, type: require('mssql').NVarChar(255) },
erpPassword: { value: erpPassword, type: require('mssql').NVarChar(255) }
})
return result.rowCount
}
/**
* Run migration for MySQL
*/
async function runMySQLMigration(configManager: ConfigManager): Promise<void> {
console.log('\n📦 Running MySQL Migration...')
// Read database config from .env file with correct key names
const mysqlHost = configManager.get('DB_MYSQL_HOST', 'localhost')
const mysqlPort = configManager.getNumber('DB_MYSQL_PORT', 3306)
const mysqlUser = configManager.get('DB_USERNAME', 'root')
const mysqlPassword = configManager.get('DB_PASSWORD', '')
const mysqlDatabase = configManager.get('DB_NAME', '')
console.log(`Connecting to MySQL: ${mysqlHost}:${mysqlPort}/${mysqlDatabase}`)
const mysqlService = new MySqlService({
host: mysqlHost,
port: mysqlPort,
user: mysqlUser,
password: mysqlPassword,
database: mysqlDatabase
})
try {
await mysqlService.connect()
console.log('✓ Connected to MySQL')
const tableName = MIGRATION_CONFIG.tableName.mysql
// Check and add columns
for (const [columnName, columnType] of [
['ERP_URL', 'VARCHAR(500)'],
['ERP_Username', 'VARCHAR(255)'],
['ERP_Password', 'VARCHAR(255)']
] as const) {
const exists = await checkColumnExistsMySQL(mysqlService, tableName, columnName)
if (exists) {
console.log(` ✓ Column ${columnName} already exists`)
} else {
await addColumnMySQL(mysqlService, tableName, columnName, columnType)
}
}
// Initialize ERP credentials from .env
const erpUrl = configManager.get('ERP_URL', '')
const erpUsername = configManager.get('ERP_USERNAME', '')
const erpPassword = configManager.get('ERP_PASSWORD', '')
if (erpUrl && erpUsername && erpPassword) {
const updatedCount = await initializeErpCredentialsMySQL(
mysqlService,
erpUrl,
erpUsername,
erpPassword
)
console.log(` ✓ Updated ${updatedCount} users with ERP credentials`)
} else {
console.log(' ⚠ Skipping ERP credential initialization (missing .env values)')
}
console.log('✅ MySQL Migration completed successfully!\n')
} catch (error) {
console.error('❌ MySQL Migration failed:', error)
throw error
} finally {
await mysqlService.disconnect()
}
}
/**
* Run migration for SQL Server
*/
async function runSqlServerMigration(configManager: ConfigManager): Promise<void> {
console.log('\n📦 Running SQL Server Migration...')
const mssql = await import('mssql')
const sqlServerService = new SqlServerService({
server: configManager.get('DB_SERVER', 'localhost'),
port: configManager.getNumber('DB_SQLSERVER_PORT', 1433),
user: configManager.get('DB_USERNAME', 'sa'),
password: configManager.get('DB_PASSWORD', ''),
database: configManager.get('DB_NAME', ''),
options: {
encrypt: false,
trustServerCertificate: configManager.get('DB_TRUST_SERVER_CERTIFICATE') === 'yes'
}
})
try {
await sqlServerService.connect()
console.log('✓ Connected to SQL Server')
const tableName = MIGRATION_CONFIG.tableName.sqlserver
// Check and add columns
for (const [columnName, columnType] of [
['ERP_URL', 'NVARCHAR(500)'],
['ERP_Username', 'NVARCHAR(255)'],
['ERP_Password', 'NVARCHAR(255)']
] as const) {
const exists = await checkColumnExistsSqlServer(sqlServerService, tableName, columnName)
if (exists) {
console.log(` ✓ Column ${columnName} already exists`)
} else {
await addColumnSqlServer(sqlServerService, tableName, columnName, columnType)
}
}
// Initialize ERP credentials from .env
const erpUrl = configManager.get('ERP_URL', '')
const erpUsername = configManager.get('ERP_USERNAME', '')
const erpPassword = configManager.get('ERP_PASSWORD', '')
if (erpUrl && erpUsername && erpPassword) {
const updatedCount = await initializeErpCredentialsSqlServer(
sqlServerService,
erpUrl,
erpUsername,
erpPassword
)
console.log(` ✓ Updated ${updatedCount} users with ERP credentials`)
} else {
console.log(' ⚠ Skipping ERP credential initialization (missing .env values)')
}
console.log('✅ SQL Server Migration completed successfully!\n')
} catch (error) {
console.error('❌ SQL Server Migration failed:', error)
throw error
} finally {
await sqlServerService.disconnect()
}
}
/**
* Main migration runner
*/
async function runMigration(): Promise<void> {
console.log('==============================================')
console.log('BIPUsers Table Migration: Add ERP Parameters')
console.log('==============================================\n')
const configManager = ConfigManager.getInstance()
await configManager.initialize()
const dbType = configManager.get('DB_TYPE', 'mysql').toLowerCase()
const isSqlServer = dbType === 'sqlserver' || dbType === 'mssql'
try {
if (isSqlServer) {
await runSqlServerMigration(configManager)
} else {
await runMySQLMigration(configManager)
}
console.log('==============================================')
console.log('Migration Summary:')
console.log('==============================================')
console.log(`Database Type: ${isSqlServer ? 'SQL Server' : 'MySQL'}`)
console.log('Columns Added/Verified:')
console.log(' - ERP_URL (VARCHAR/NVARCHAR 500)')
console.log(' - ERP_Username (VARCHAR/NVARCHAR 255)')
console.log(' - ERP_Password (VARCHAR/NVARCHAR 255)')
console.log('==============================================\n')
} catch (error) {
console.error('\n❌ Migration failed with error:', error)
process.exit(1)
}
}
// Run migration
runMigration().catch((error) => {
console.error('Unexpected error:', error)
process.exit(1)
})

View File

@@ -0,0 +1,89 @@
-- ============================================
-- BIPUsers Table Migration: Add ERP Parameters
-- Database: MySQL
-- ============================================
-- This script adds three new columns to store ERP connection parameters:
-- - ERP_URL: The ERP system URL
-- - ERP_Username: The ERP username
-- - ERP_Password: The ERP password
--
-- Usage: Run this script in your MySQL client
-- Example: mysql -u root -p BLD_DB < add-erp-params-to-bipusers-mysql.sql
-- ============================================
USE BLD_DB;
-- Add ERP_URL column if not exists
SET @dbname = DATABASE();
SET @tablename = 'dbo_BIPUsers';
SET @columnname = 'ERP_URL';
SET @preparedStatement = (SELECT IF(
(
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE
(table_name = @tablename)
AND (table_schema = @dbname)
AND (column_name = @columnname)
) > 0,
'SELECT 1',
CONCAT('ALTER TABLE ', @tablename, ' ADD COLUMN ', @columnname, ' VARCHAR(500) NULL')
));
PREPARE alterIfNotExists FROM @preparedStatement;
EXECUTE alterIfNotExists;
DEALLOCATE PREPARE alterIfNotExists;
-- Add ERP_Username column if not exists
SET @columnname = 'ERP_Username';
SET @preparedStatement = (SELECT IF(
(
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE
(table_name = @tablename)
AND (table_schema = @dbname)
AND (column_name = @columnname)
) > 0,
'SELECT 1',
CONCAT('ALTER TABLE ', @tablename, ' ADD COLUMN ', @columnname, ' VARCHAR(255) NULL')
));
PREPARE alterIfNotExists FROM @preparedStatement;
EXECUTE alterIfNotExists;
DEALLOCATE PREPARE alterIfNotExists;
-- Add ERP_Password column if not exists
SET @columnname = 'ERP_Password';
SET @preparedStatement = (SELECT IF(
(
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE
(table_name = @tablename)
AND (table_schema = @dbname)
AND (column_name = @columnname)
) > 0,
'SELECT 1',
CONCAT('ALTER TABLE ', @tablename, ' ADD COLUMN ', @columnname, ' VARCHAR(255) NULL')
));
PREPARE alterIfNotExists FROM @preparedStatement;
EXECUTE alterIfNotExists;
DEALLOCATE PREPARE alterIfNotExists;
-- Verify columns were added
SELECT
COLUMN_NAME,
DATA_TYPE,
CHARACTER_MAXIMUM_LENGTH,
IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'dbo_BIPUsers'
AND COLUMN_NAME IN ('ERP_URL', 'ERP_Username', 'ERP_Password');
-- Optional: Update all existing users with the same ERP credentials
-- Replace the values below with your actual ERP credentials
-- Example:
-- UPDATE dbo_BIPUsers
-- SET ERP_URL = 'https://68.11.34.30:8082/',
-- ERP_Username = 'your_username',
-- ERP_Password = 'your_password'
-- WHERE ERP_URL IS NULL;
SELECT 'Migration completed successfully!' AS status;

View File

@@ -0,0 +1,114 @@
/**
* Database Migration Script
* Add ERP configuration fields to dbo_BIPUsers table
*
* This script adds three new columns to store ERP connection parameters:
* - ERP_URL: The ERP system URL
* - ERP_USERNAME: The ERP username
* - ERP_PASSWORD: The ERP password (encrypted in production)
*
* IMPORTANT:
* - For SQL Server: Run this script on the SQL Server database
* - For MySQL: Run this script on the MySQL database (syntax is auto-detected)
* - All existing users will have the same ERP credentials (to be configured individually later)
*/
-- ===========================================
-- SQL Server Version
-- ===========================================
-- Uncomment and run this section for SQL Server
/*
IF NOT EXISTS (SELECT * FROM sys.columns
WHERE object_id = OBJECT_ID(N'[dbo].[BIPUsers]')
AND name = 'ERP_URL')
BEGIN
ALTER TABLE [dbo].[BIPUsers]
ADD ERP_URL NVARCHAR(500) NULL;
ALTER TABLE [dbo].[BIPUsers]
ADD ERP_Username NVARCHAR(255) NULL;
ALTER TABLE [dbo].[BIPUsers]
ADD ERP_Password NVARCHAR(255) NULL;
PRINT 'ERP columns added successfully to [dbo].[BIPUsers]';
END
ELSE
BEGIN
PRINT 'ERP columns already exist in [dbo].[BIPUsers]';
END
-- Optional: Update all existing users with the same ERP credentials
-- Replace the values below with your actual ERP credentials
-- UPDATE [dbo].[BIPUsers]
-- SET ERP_URL = 'https://your-erp-system.com',
-- ERP_Username = 'your_username',
-- ERP_Password = 'your_password'
-- WHERE ERP_URL IS NULL;
*/
-- ===========================================
-- MySQL Version
-- ===========================================
-- Run this section for MySQL
-- Add ERP_URL column if not exists
SET @dbname = DATABASE();
SET @tablename = 'dbo_BIPUsers';
SET @columnname = 'ERP_URL';
SET @preparedStatement = (SELECT IF(
(
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE
(table_name = @tablename)
AND (table_schema = @dbname)
AND (column_name = @columnname)
) > 0,
'SELECT 1',
CONCAT('ALTER TABLE ', @tablename, ' ADD COLUMN ', @columnname, ' VARCHAR(500) NULL')
));
PREPARE alterIfNotExists FROM @preparedStatement;
EXECUTE alterIfNotExists;
DEALLOCATE PREPARE alterIfNotExists;
-- Add ERP_Username column if not exists
SET @columnname = 'ERP_Username';
SET @preparedStatement = (SELECT IF(
(
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE
(table_name = @tablename)
AND (table_schema = @dbname)
AND (column_name = @columnname)
) > 0,
'SELECT 1',
CONCAT('ALTER TABLE ', @tablename, ' ADD COLUMN ', @columnname, ' VARCHAR(255) NULL')
));
PREPARE alterIfNotExists FROM @preparedStatement;
EXECUTE alterIfNotExists;
DEALLOCATE PREPARE alterIfNotExists;
-- Add ERP_Password column if not exists
SET @columnname = 'ERP_Password';
SET @preparedStatement = (SELECT IF(
(
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE
(table_name = @tablename)
AND (table_schema = @dbname)
AND (column_name = @columnname)
) > 0,
'SELECT 1',
CONCAT('ALTER TABLE ', @tablename, ' ADD COLUMN ', @columnname, ' VARCHAR(255) NULL')
));
PREPARE alterIfNotExists FROM @preparedStatement;
EXECUTE alterIfNotExists;
DEALLOCATE PREPARE alterIfNotExists;
-- Optional: Update all existing users with the same ERP credentials
-- Replace the values below with your actual ERP credentials
-- UPDATE dbo_BIPUsers
-- SET ERP_URL = 'https://your-erp-system.com',
-- ERP_Username = 'your_username',
-- ERP_Password = 'your_password'
-- WHERE ERP_URL IS NULL;

View File

@@ -0,0 +1,98 @@
-- ============================================
-- BIPUsers 表迁移:添加 ERP 参数字段
-- 数据库MySQL
-- 目标数据库BLD_DB
-- ============================================
-- 使用说明:
-- 1. 在 MySQL Workbench / Navicat / DBeaver 中打开此文件
-- 2. 连接到数据库 192.168.31.83:3306/BLD_DB
-- 3. 执行全部 SQL 语句
-- ============================================
-- 切换到目标数据库
USE BLD_DB;
-- ============================================
-- 步骤 1: 添加新字段
-- ============================================
-- 添加 ERP_URL 字段(如果不存在)
-- 注意:如果 MySQL 版本不支持 ADD COLUMN IF NOT EXISTS请移除 IF NOT EXISTS
ALTER TABLE dbo_BIPUsers
ADD COLUMN ERP_URL VARCHAR(500) NULL COMMENT 'ERP 系统 URL';
-- 添加 ERP_Username 字段
ALTER TABLE dbo_BIPUsers
ADD COLUMN ERP_Username VARCHAR(255) NULL COMMENT 'ERP 用户名';
-- 添加 ERP_Password 字段
ALTER TABLE dbo_BIPUsers
ADD COLUMN ERP_Password VARCHAR(255) NULL COMMENT 'ERP 密码';
-- ============================================
-- 步骤 2: 验证字段已添加
-- ============================================
-- 显示表结构,确认新字段已添加
SELECT '字段添加验证' AS step;
DESCRIBE dbo_BIPUsers;
-- 或者使用以下查询确认新字段
SELECT
COLUMN_NAME AS '字段名',
DATA_TYPE AS '数据类型',
CHARACTER_MAXIMUM_LENGTH AS '最大长度',
IS_NULLABLE AS '允许 NULL',
COLUMN_COMMENT AS '注释'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'BLD_DB'
AND TABLE_NAME = 'dbo_BIPUsers'
AND COLUMN_NAME IN ('ERP_URL', 'ERP_Username', 'ERP_Password')
ORDER BY COLUMN_NAME;
-- ============================================
-- 步骤 3: 初始化 ERP 配置
-- 注意:请根据实际情况修改下面的配置值!
-- ============================================
SELECT '=== 请修改下面的 ERP 配置值 ===' AS notice;
SELECT '当前数据库中的用户:' AS notice;
SELECT UserName, UserType, ComputerName FROM dbo_BIPUsers ORDER BY UserName;
-- 更新所有用户的 ERP 配置
-- ⚠️ 请修改下面的配置值为你实际的 ERP 凭证!
UPDATE dbo_BIPUsers
SET
ERP_URL = 'https://68.11.34.30:8082/', -- 修改为你的 ERP 系统 URL
ERP_Username = 'your_erp_username', -- 修改为你的 ERP 用户名
ERP_Password = 'your_erp_password' -- 修改为你的 ERP 密码
WHERE ERP_URL IS NULL OR ERP_URL = '';
-- 显示更新后的结果
SELECT
'更新后的 ERP 配置' AS notice,
UserName,
ERP_URL,
ERP_Username
FROM dbo_BIPUsers
ORDER BY UserName;
-- ============================================
-- 步骤 4: 完成确认
-- ============================================
SELECT '================================' AS '';
SELECT '迁移完成!' AS message;
SELECT '================================' AS '';
SELECT '请确认:' AS notice;
SELECT '1. 所有用户都有 ERP_URL 配置' AS check1;
SELECT '2. ERP_URL 格式正确' AS check2;
SELECT '3. ERP 用户名和密码正确' AS check3;
SELECT '================================' AS '';
-- 统计信息
SELECT
COUNT(*) AS total_users,
COUNT(ERP_URL) AS users_with_erp_url,
COUNT(ERP_Username) AS users_with_erp_username
FROM dbo_BIPUsers;

View File

@@ -0,0 +1,184 @@
/**
* Simple Migration Script: Add ERP parameters to BIPUsers table
*
* This script adds ERP_URL, ERP_Username, and ERP_Password columns
* to the dbo_BIPUsers table.
*
* Usage:
* npx tsx src/main/services/user/migration/run-migration.ts
*/
import * as mysql from 'mysql2/promise'
import * as fs from 'fs'
import * as path from 'path'
import { fileURLToPath } from 'url'
import { dirname } from 'path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
/**
* Load .env file manually
*/
function loadEnv(filePath: string): Map<string, string> {
const envMap = new Map<string, string>()
if (!fs.existsSync(filePath)) {
console.warn(`.env file not found: ${filePath}`)
return envMap
}
const content = fs.readFileSync(filePath, 'utf-8')
const lines = content.split('\n')
for (const line of lines) {
const trimmedLine = line.trim()
if (!trimmedLine || trimmedLine.startsWith('#')) {
continue
}
const [key, ...valueParts] = trimmedLine.split('=')
if (key && valueParts.length > 0) {
const value = valueParts.join('=').trim()
envMap.set(key.trim(), value)
}
}
return envMap
}
/**
* Check if column exists in MySQL table
*/
async function checkColumnExists(
connection: mysql.Connection,
tableName: string,
columnName: string
): Promise<boolean> {
const sql = `
SELECT COUNT(*) as count
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = ?
AND COLUMN_NAME = ?
`
const [rows] = await connection.query(sql, [tableName, columnName])
const result = rows as any[]
return result.length > 0 && result[0].count > 0
}
/**
* Add column to MySQL table
*/
async function addColumn(
connection: mysql.Connection,
tableName: string,
columnName: string,
columnType: string
): Promise<void> {
const sql = `ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${columnType} NULL`
await connection.query(sql)
console.log(` ✓ Added column ${columnName} to ${tableName}`)
}
/**
* Main migration function
*/
async function runMigration(): Promise<void> {
console.log('==============================================')
console.log('BIPUsers Table Migration: Add ERP Parameters')
console.log('==============================================\n')
// Load .env file from project root
const envPath = path.resolve(process.cwd(), '.env')
console.log(`Loading .env from: ${envPath}`)
const env = loadEnv(envPath)
// Get database configuration
const dbHost = env.get('DB_MYSQL_HOST') || 'localhost'
const dbPort = parseInt(env.get('DB_MYSQL_PORT') || '3306', 10)
const dbUser = env.get('DB_USERNAME') || 'root'
const dbPassword = env.get('DB_PASSWORD') || ''
const dbName = env.get('DB_NAME') || ''
console.log(`Database: ${dbHost}:${dbPort}/${dbName}`)
console.log(`Username: ${dbUser}`)
console.log('')
let connection: mysql.Connection | null = null
try {
// Connect to MySQL
console.log('Connecting to MySQL...')
connection = await mysql.createConnection({
host: dbHost,
port: dbPort,
user: dbUser,
password: dbPassword,
database: dbName
})
console.log('✓ Connected to MySQL\n')
const tableName = 'dbo_BIPUsers'
// Check and add columns
console.log('Checking columns...')
for (const [columnName, columnType] of [
['ERP_URL', 'VARCHAR(500)'],
['ERP_Username', 'VARCHAR(255)'],
['ERP_Password', 'VARCHAR(255)']
] as const) {
const exists = await checkColumnExists(connection, tableName, columnName)
if (exists) {
console.log(` ✓ Column ${columnName} already exists`)
} else {
await addColumn(connection, tableName, columnName, columnType)
}
}
console.log('\n==============================================')
console.log('Migration Summary:')
console.log('==============================================')
console.log('Database Type: MySQL')
console.log('Database: ' + dbName)
console.log('Columns Added/Verified:')
console.log(' - ERP_URL (VARCHAR 500)')
console.log(' - ERP_Username (VARCHAR 255)')
console.log(' - ERP_Password (VARCHAR 255)')
console.log('==============================================')
console.log('\n✅ Migration completed successfully!\n')
console.log('Next steps:')
console.log('1. Update ERP credentials for users in dbo_BIPUsers table')
console.log('2. Example SQL:')
console.log(` UPDATE ${tableName}`)
console.log(` SET ERP_URL = 'https://your-erp.com',`)
console.log(` ERP_Username = 'your_username',`)
console.log(` ERP_Password = 'your_password'`)
console.log(` WHERE ERP_URL IS NULL;\n`)
} catch (error) {
console.error('\n❌ Migration failed with error:')
console.error(error)
console.error('\nTroubleshooting:')
console.error('1. Check if MySQL server is running')
console.error('2. Verify database credentials in .env file')
console.error('3. Ensure database "' + dbName + '" exists')
console.error('4. Check network connectivity to ' + dbHost + ':' + dbPort)
process.exit(1)
} finally {
// Disconnect
if (connection) {
try {
await connection.end()
console.log('Disconnected from MySQL')
} catch (e) {
// Ignore disconnect errors
}
}
}
}
// Run migration
runMigration().catch((error) => {
console.error('Unexpected error:', error)
process.exit(1)
})

View File

@@ -0,0 +1,200 @@
/**
* User ERP Configuration Service
*
* Manages ERP configuration (URL, username, password) stored in the BIPUsers table.
* Each user can have their own ERP credentials.
*
* Features:
* - Get current user's ERP config
* - Update current user's ERP config
* - Get ERP config for any user (admin only)
*/
import { BIPUsersDAO } from './bip-users-dao'
import { SessionManager } from './session-manager'
import { createLogger } from '../logger'
const log = createLogger('UserErpConfigService')
/**
* ERP Configuration object
*/
export interface ErpConfig {
url: string
username: string
password: string
}
/**
* User ERP Configuration Service Class
*/
export class UserErpConfigService {
private static instance: UserErpConfigService | null = null
private dao: BIPUsersDAO
private constructor() {
this.dao = new BIPUsersDAO()
}
/**
* Get the singleton instance
*/
public static getInstance(): UserErpConfigService {
if (UserErpConfigService.instance === null) {
UserErpConfigService.instance = new UserErpConfigService()
}
return UserErpConfigService.instance
}
/**
* Get ERP configuration for the current authenticated user
* @returns ERP configuration or null if not found
*/
async getCurrentUserErpConfig(): Promise<ErpConfig | null> {
try {
const sessionManager = SessionManager.getInstance()
const currentUser = sessionManager.getUserInfo()
if (!currentUser) {
log.warn('No authenticated user found')
return null
}
log.info('Fetching ERP config for user', { username: currentUser.username })
const config = await this.dao.getUserErpConfig(currentUser.username)
if (!config) {
log.warn('No ERP config found for user', { username: currentUser.username })
return null
}
log.info('ERP config retrieved successfully', {
username: currentUser.username,
hasUrl: !!config.url,
hasUsername: !!config.username,
hasPassword: !!config.password
})
return config
} catch (error) {
log.error('Error getting current user ERP config', { error })
return null
}
}
/**
* Get ERP configuration for a specific user (admin only)
* @param username - The username to get ERP config for
* @returns ERP configuration or null if not found
*/
async getUserErpConfig(username: string): Promise<ErpConfig | null> {
try {
log.info('Fetching ERP config for user', { username })
const config = await this.dao.getUserErpConfig(username)
if (!config) {
log.warn('No ERP config found for user', { username })
return null
}
return config
} catch (error) {
log.error('Error getting user ERP config', { error })
return null
}
}
/**
* Update ERP configuration for the current authenticated user
* @param config - ERP configuration to save
* @returns True if successful
*/
async updateCurrentUserErpConfig(config: ErpConfig): Promise<boolean> {
try {
const sessionManager = SessionManager.getInstance()
const currentUser = sessionManager.getUserInfo()
if (!currentUser) {
log.warn('No authenticated user found')
return false
}
log.info('Updating ERP config for user', { username: currentUser.username })
const success = await this.dao.updateUserErpConfig(
currentUser.username,
config.url,
config.username,
config.password
)
if (success) {
log.info('ERP config updated successfully', { username: currentUser.username })
} else {
log.error('Failed to update ERP config', { username: currentUser.username })
}
return success
} catch (error) {
log.error('Error updating current user ERP config', { error })
return false
}
}
/**
* Update ERP configuration for a specific user (admin only)
* @param username - The username to update ERP config for
* @param config - ERP configuration to save
* @returns True if successful
*/
async updateUserErpConfig(username: string, config: ErpConfig): Promise<boolean> {
try {
log.info('Updating ERP config for user', { username })
const success = await this.dao.updateUserErpConfig(
username,
config.url,
config.username,
config.password
)
if (success) {
log.info('ERP config updated successfully', { username })
} else {
log.error('Failed to update ERP config', { username })
}
return success
} catch (error) {
log.error('Error updating user ERP config', { error })
return false
}
}
/**
* Get ERP configuration for all users (admin only, for migration/audit)
* @returns List of users with their ERP configurations
*/
async getAllUsersErpConfig(): Promise<
Array<{
username: string
erpUrl: string
erpUsername: string
}>
> {
try {
log.info('Fetching ERP config for all users')
const configs = await this.dao.getAllUsersErpConfig()
log.info('Retrieved ERP configs for all users', { count: configs.length })
return configs
} catch (error) {
log.error('Error getting all users ERP config', { error })
return []
}
}
/**
* Disconnect from database
*/
async disconnect(): Promise<void> {
await this.dao.disconnect()
}
}