refactor(ipc): harden channels and unify IPC contracts

This commit is contained in:
test
2026-03-08 12:35:00 +08:00
parent 616e2b31a5
commit 8f3e5273e2
25 changed files with 991 additions and 1263 deletions

View File

@@ -1,16 +1,3 @@
/**
* Settings IPC Handler
*
* Provides IPC handlers for settings management:
* - Get/set ERP credentials (stored in database per user)
* - Reset to defaults (Admin only)
* - Test database connection
*
* Note: ERP configuration is stored in database (dbo_BIPUsers table)
* and managed per-user via UserErpConfigService.
* Other settings (database, paths, etc.) are managed via config.yaml
*/
import { ipcMain } from 'electron'
import { ConfigManager } from '../services/config/config-manager'
import { SessionManager } from '../services/user/session-manager'
@@ -19,156 +6,129 @@ import { MySqlService } from '../services/database/mysql'
import { SqlServerService } from '../services/database/sql-server'
import { createLogger } from '../services/logger'
import type { UserType, ConnectionTestResult, SaveSettingsResult } from '../types/settings.types'
import { IPC_CHANNELS } from '../../shared/ipc-channels'
import { ValidationError } from '../types/errors'
import { withErrorHandling, type IpcResult } from './index'
const log = createLogger('SettingsHandler')
/**
* Register IPC handlers for settings management
*/
type ErpSettingsPayload = {
erp?: {
username?: string
password?: string
}
}
export function registerSettingsHandlers(): void {
const configManager = ConfigManager.getInstance()
const sessionManager = SessionManager.getInstance()
const erpConfigService = UserErpConfigService.getInstance()
/**
* Get current user type
*/
ipcMain.handle('settings:getUserType', async (): Promise<UserType> => {
return (sessionManager.getUserType() as UserType) || 'Guest'
ipcMain.handle(IPC_CHANNELS.SETTINGS_GET_USER_TYPE, async (): Promise<IpcResult<UserType>> => {
return withErrorHandling(
async () => (sessionManager.getUserType() as UserType) || 'Guest',
'settings:getUserType'
)
})
/**
* Get ERP credentials for current user
*/
ipcMain.handle('settings:getSettings', async (): Promise<any> => {
try {
// Get ERP credentials from database for current user
const userErpConfig = await erpConfigService.getCurrentUserErpConfig()
return {
erp: {
username: userErpConfig?.username || '',
password: userErpConfig?.password || ''
}
}
} catch (error) {
log.error('Failed to get ERP credentials', { error })
return { erp: { username: '', password: '' } }
}
})
/**
* Save ERP credentials for current user
*/
ipcMain.handle(
'settings:saveSettings',
async (_event, settings: any): Promise<SaveSettingsResult> => {
try {
log.info('Saving ERP credentials')
if (settings.erp) {
// Update ERP credentials in database for current user
const currentUser = sessionManager.getUserInfo()
if (!currentUser) {
return { success: false, error: '未找到当前用户' }
IPC_CHANNELS.SETTINGS_GET_SETTINGS,
async (): Promise<IpcResult<{ erp: { username: string; password: string } }>> => {
return withErrorHandling(async () => {
const userErpConfig = await erpConfigService.getCurrentUserErpConfig()
return {
erp: {
username: userErpConfig?.username || '',
password: userErpConfig?.password || ''
}
// Ensure undefined values are converted to empty strings
const erpCredentials = {
username: settings.erp.username || '',
password: settings.erp.password || ''
}
await erpConfigService.updateCurrentUserErpConfig(erpCredentials)
log.info('ERP credentials saved successfully')
}
return { success: true }
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error'
log.error('Error saving ERP credentials', { error: message })
return { success: false, error: `保存配置失败:${message}` }
}
}, 'settings:getSettings')
}
)
/**
* Reset to default settings (Admin only)
*/
ipcMain.handle('settings:resetDefaults', async (): Promise<SaveSettingsResult> => {
try {
const userType = sessionManager.getUserType()
if (userType !== 'Admin') {
log.warn('Non-admin user attempted to reset defaults', { userType })
return { success: false, error: '只有管理员可以恢复默认设置' }
}
ipcMain.handle(
IPC_CHANNELS.SETTINGS_SAVE_SETTINGS,
async (_event, settings: ErpSettingsPayload): Promise<IpcResult<SaveSettingsResult>> => {
return withErrorHandling(async () => {
if (settings.erp) {
const currentUser = sessionManager.getUserInfo()
if (!currentUser) {
throw new ValidationError('未找到当前用户', 'VAL_INVALID_INPUT')
}
await erpConfigService.updateCurrentUserErpConfig({
username: settings.erp.username || '',
password: settings.erp.password || ''
})
}
log.info('Resetting settings to defaults')
const success = await configManager.resetToDefaults()
if (success) {
log.info('Settings reset to defaults successfully')
return { success: true }
} else {
log.warn('Failed to reset settings to defaults')
return { success: false, error: '恢复默认设置失败' }
}
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error'
log.error('Error resetting settings', { error: message })
return { success: false, error: `恢复默认设置失败:${message}` }
}, 'settings:saveSettings')
}
})
)
/**
* Test database connection
*/
ipcMain.handle('settings:testDbConnection', async (): Promise<ConnectionTestResult> => {
try {
log.info('Testing database connection')
const config = configManager.getConfig()
const dbType = config.database.activeType
ipcMain.handle(
IPC_CHANNELS.SETTINGS_RESET_DEFAULTS,
async (): Promise<IpcResult<SaveSettingsResult>> => {
return withErrorHandling(async () => {
const userType = sessionManager.getUserType()
if (userType !== 'Admin') {
throw new ValidationError('只有管理员可以恢复默认设置', 'VAL_INVALID_INPUT')
}
if (dbType === 'mysql') {
// Test MySQL connection
const dbConfig = config.database.mysql
if (!dbConfig.host || !dbConfig.database || !dbConfig.username) {
log.warn('MySQL connection test failed - missing configuration')
return {
success: false,
message: '请先配置 MySQL 主机、数据库名和用户名'
const success = await configManager.resetToDefaults()
if (!success) {
throw new ValidationError('恢复默认设置失败', 'VAL_INVALID_INPUT')
}
return { success: true }
}, 'settings:resetDefaults')
}
)
ipcMain.handle(
IPC_CHANNELS.SETTINGS_TEST_DB_CONNECTION,
async (): Promise<IpcResult<ConnectionTestResult>> => {
return withErrorHandling(async () => {
log.info('Testing database connection')
const config = configManager.getConfig()
const dbType = config.database.activeType
if (dbType === 'mysql') {
const dbConfig = config.database.mysql
if (!dbConfig.host || !dbConfig.database || !dbConfig.username) {
return {
success: false,
message: '请先配置 MySQL 主机、数据库名和用户名'
}
}
const mysqlService = new MySqlService({
host: dbConfig.host,
port: dbConfig.port,
user: dbConfig.username,
password: dbConfig.password,
database: dbConfig.database
})
try {
await mysqlService.connect()
await mysqlService.disconnect()
return {
success: true,
message: 'MySQL 数据库连接测试成功!'
}
} catch (error) {
const message = error instanceof Error ? error.message : '连接失败'
return {
success: false,
message: `MySQL 数据库连接测试失败:${message}`
}
}
}
const mysqlService = new MySqlService({
host: dbConfig.host,
port: dbConfig.port,
user: dbConfig.username,
password: dbConfig.password,
database: dbConfig.database
})
try {
await mysqlService.connect()
await mysqlService.disconnect()
log.info('MySQL connection test successful')
return {
success: true,
message: 'MySQL 数据库连接测试成功!'
}
} catch (connError) {
const errorMessage = connError instanceof Error ? connError.message : '连接失败'
log.error('MySQL connection failed', { error: errorMessage })
return {
success: false,
message: `MySQL 数据库连接测试失败:${errorMessage}`
}
}
} else {
// Test SQL Server connection
const dbConfig = config.database.sqlserver
if (!dbConfig.server || !dbConfig.database || !dbConfig.username) {
log.warn('SQL Server connection test failed - missing configuration')
return {
success: false,
message: '请先配置 SQL Server 服务器、数据库名和用户名'
@@ -189,27 +149,19 @@ export function registerSettingsHandlers(): void {
try {
await sqlServerService.connect()
await sqlServerService.disconnect()
log.info('SQL Server connection test successful')
return {
success: true,
message: 'SQL Server 数据库连接测试成功!'
}
} catch (connError) {
const errorMessage = connError instanceof Error ? connError.message : '连接失败'
log.error('SQL Server connection failed', { error: errorMessage })
} catch (error) {
const message = error instanceof Error ? error.message : '连接失败'
return {
success: false,
message: `SQL Server 数据库连接测试失败:${errorMessage}`
message: `SQL Server 数据库连接测试失败:${message}`
}
}
}
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error'
log.error('Database connection test error', { error: message })
return {
success: false,
message: `数据库连接测试失败:${message}`
}
}, 'settings:testDbConnection')
}
})
)
}