refactor(ipc): harden channels and unify IPC contracts
This commit is contained in:
@@ -61,16 +61,18 @@ function App(): React.JSX.Element {
|
||||
try {
|
||||
// Get computer name
|
||||
console.log('Getting computer name...')
|
||||
const name = await window.electron.auth.getComputerName()
|
||||
const computerNameResult = await window.electron.auth.getComputerName()
|
||||
const name = computerNameResult.success && computerNameResult.data ? computerNameResult.data : ''
|
||||
console.log('Computer name:', name)
|
||||
setComputerName(name)
|
||||
|
||||
// Try silent login
|
||||
console.log('Trying silent login...')
|
||||
const result = await window.electron.auth.silentLogin()
|
||||
const silentLoginResult = await window.electron.auth.silentLogin()
|
||||
const result = silentLoginResult.data
|
||||
console.log('Silent login result:', result)
|
||||
|
||||
if (result.success && result.userInfo) {
|
||||
if (silentLoginResult.success && result?.success && result.userInfo) {
|
||||
console.log('Silent login success:', result.userInfo)
|
||||
setCurrentUser({
|
||||
username: result.userInfo.username,
|
||||
@@ -81,8 +83,8 @@ function App(): React.JSX.Element {
|
||||
if (result.requiresUserSelection) {
|
||||
console.log('Admin user needs to select user')
|
||||
// Load all users for selection
|
||||
const users = await window.electron.auth.getAllUsers()
|
||||
setAllUsers(users)
|
||||
const usersResult = await window.electron.auth.getAllUsers()
|
||||
setAllUsers(usersResult.success && usersResult.data ? usersResult.data : [])
|
||||
setShowUserSelection(true)
|
||||
} else {
|
||||
console.log('Setting authenticated to true')
|
||||
@@ -107,19 +109,20 @@ function App(): React.JSX.Element {
|
||||
const handleLogin = async (username: string, password: string): Promise<boolean> => {
|
||||
try {
|
||||
const result = await window.electron.auth.login({ username, password })
|
||||
const loginData = result.success ? result.data : undefined
|
||||
|
||||
if (result.success && result.userInfo) {
|
||||
if (result.success && loginData?.userInfo) {
|
||||
setCurrentUser({
|
||||
username: result.userInfo.username,
|
||||
userType: result.userInfo.userType
|
||||
username: loginData.userInfo.username,
|
||||
userType: loginData.userInfo.userType
|
||||
})
|
||||
|
||||
// Check if admin needs user selection
|
||||
if (result.userInfo.userType === 'Admin') {
|
||||
if (loginData.userInfo.userType === 'Admin') {
|
||||
setShowLoginDialog(false)
|
||||
// Load all users for selection
|
||||
const users = await window.electron.auth.getAllUsers()
|
||||
setAllUsers(users)
|
||||
const usersResult = await window.electron.auth.getAllUsers()
|
||||
setAllUsers(usersResult.success && usersResult.data ? usersResult.data : [])
|
||||
setShowUserSelection(true)
|
||||
} else {
|
||||
setIsAuthenticated(true)
|
||||
@@ -144,10 +147,11 @@ function App(): React.JSX.Element {
|
||||
const handleUserSelect = async (user: SelectedUserInfo) => {
|
||||
try {
|
||||
const result = await window.electron.auth.switchUser(user)
|
||||
if (result.success) {
|
||||
const switchData = result.success ? result.data : undefined
|
||||
if (result.success && switchData) {
|
||||
setCurrentUser({
|
||||
username: result.userInfo?.username || user.username,
|
||||
userType: result.userInfo?.userType || user.userType
|
||||
username: switchData.userInfo?.username || user.username,
|
||||
userType: switchData.userInfo?.userType || user.userType
|
||||
})
|
||||
setIsAuthenticated(true)
|
||||
setShowUserSelection(false)
|
||||
|
||||
@@ -252,10 +252,11 @@ export const MaterialTypeManagementDialog: React.FC<MaterialTypeManagementDialog
|
||||
toUpdate,
|
||||
toDelete
|
||||
})
|
||||
const payload = result.success ? (result.data as { stats?: { success?: number; failed?: number } } | undefined) : undefined
|
||||
|
||||
if (result.success) {
|
||||
alert(
|
||||
`保存完成!\n成功:${result.stats?.success || 0} 条\n失败:${result.stats?.failed || 0} 条`
|
||||
`保存完成!\n成功:${payload?.stats?.success || 0} 条\n失败:${payload?.stats?.failed || 0} 条`
|
||||
)
|
||||
await loadData()
|
||||
} else {
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
/**
|
||||
* IPC Hook for Authentication operations
|
||||
*
|
||||
* Provides a React-friendly interface for auth IPC calls
|
||||
* with loading state, error handling, and user data management.
|
||||
*/
|
||||
|
||||
import { useState, useCallback } from 'react'
|
||||
|
||||
// Types based on the user types
|
||||
interface UserInfo {
|
||||
id: number
|
||||
username: string
|
||||
@@ -38,9 +30,6 @@ interface UseAuthReturn extends UseAuthState {
|
||||
reset: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for authentication operations
|
||||
*/
|
||||
export function useAuth(): UseAuthReturn {
|
||||
const [state, setState] = useState<UseAuthState>({
|
||||
loading: false,
|
||||
@@ -51,156 +40,94 @@ export function useAuth(): UseAuthReturn {
|
||||
|
||||
const login = useCallback(async (credentials: LoginCredentials): Promise<boolean> => {
|
||||
setState((prev) => ({ ...prev, loading: true, error: null }))
|
||||
const result = await window.electron.auth.login(credentials)
|
||||
|
||||
try {
|
||||
const result = (await window.electron.ipcRenderer.invoke('auth:login', credentials)) as {
|
||||
success: boolean
|
||||
userInfo?: UserInfo
|
||||
error?: string
|
||||
}
|
||||
|
||||
if (result.success && result.userInfo) {
|
||||
setState({
|
||||
loading: false,
|
||||
user: result.userInfo,
|
||||
error: null,
|
||||
isAuthenticated: true
|
||||
})
|
||||
return true
|
||||
} else {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
loading: false,
|
||||
error: result.error || 'Login failed'
|
||||
}))
|
||||
return false
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Unknown error'
|
||||
setState((prev) => ({ ...prev, loading: false, error: message }))
|
||||
if (!result.success || !result.data?.userInfo) {
|
||||
setState((prev) => ({ ...prev, loading: false, error: result.error ?? 'Login failed' }))
|
||||
return false
|
||||
}
|
||||
|
||||
setState({
|
||||
loading: false,
|
||||
user: result.data.userInfo,
|
||||
error: null,
|
||||
isAuthenticated: true
|
||||
})
|
||||
return true
|
||||
}, [])
|
||||
|
||||
const silentLogin = useCallback(async (): Promise<{
|
||||
success: boolean
|
||||
requiresUserSelection?: boolean
|
||||
}> => {
|
||||
const silentLogin = useCallback(async (): Promise<{ success: boolean; requiresUserSelection?: boolean }> => {
|
||||
setState((prev) => ({ ...prev, loading: true, error: null }))
|
||||
const result = await window.electron.auth.silentLogin()
|
||||
|
||||
try {
|
||||
const result = (await window.electron.ipcRenderer.invoke('auth:silentLogin')) as {
|
||||
success: boolean
|
||||
userInfo?: UserInfo
|
||||
error?: string
|
||||
requiresUserSelection?: boolean
|
||||
}
|
||||
|
||||
if (result.success && result.userInfo) {
|
||||
setState({
|
||||
loading: false,
|
||||
user: result.userInfo,
|
||||
error: null,
|
||||
isAuthenticated: true
|
||||
})
|
||||
return { success: true, requiresUserSelection: result.requiresUserSelection }
|
||||
} else {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
loading: false,
|
||||
error: result.error || null
|
||||
}))
|
||||
return { success: false }
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Unknown error'
|
||||
setState((prev) => ({ ...prev, loading: false, error: message }))
|
||||
if (!result.success || !result.data?.userInfo) {
|
||||
setState((prev) => ({ ...prev, loading: false, error: result.error || null }))
|
||||
return { success: false }
|
||||
}
|
||||
|
||||
setState({
|
||||
loading: false,
|
||||
user: result.data.userInfo,
|
||||
error: null,
|
||||
isAuthenticated: true
|
||||
})
|
||||
return { success: true, requiresUserSelection: result.data.requiresUserSelection }
|
||||
}, [])
|
||||
|
||||
const logout = useCallback(async (): Promise<void> => {
|
||||
try {
|
||||
await window.electron.ipcRenderer.invoke('auth:logout')
|
||||
setState({
|
||||
loading: false,
|
||||
user: null,
|
||||
error: null,
|
||||
isAuthenticated: false
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Logout error:', error)
|
||||
}
|
||||
await window.electron.auth.logout()
|
||||
setState({
|
||||
loading: false,
|
||||
user: null,
|
||||
error: null,
|
||||
isAuthenticated: false
|
||||
})
|
||||
}, [])
|
||||
|
||||
const getCurrentUser = useCallback(async (): Promise<UserInfo | null> => {
|
||||
try {
|
||||
const result = (await window.electron.ipcRenderer.invoke('auth:getCurrentUser')) as {
|
||||
isAuthenticated: boolean
|
||||
userInfo?: UserInfo
|
||||
}
|
||||
if (result.isAuthenticated && result.userInfo) {
|
||||
const userInfo = result.userInfo
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
user: userInfo,
|
||||
isAuthenticated: true
|
||||
}))
|
||||
return userInfo
|
||||
}
|
||||
return null
|
||||
} catch {
|
||||
const result = await window.electron.auth.getCurrentUser()
|
||||
if (!result.success || !result.data?.isAuthenticated || !result.data.userInfo) {
|
||||
return null
|
||||
}
|
||||
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
user: result.data!.userInfo!,
|
||||
isAuthenticated: true
|
||||
}))
|
||||
return result.data.userInfo
|
||||
}, [])
|
||||
|
||||
const getAllUsers = useCallback(async (): Promise<UserInfo[]> => {
|
||||
try {
|
||||
return (await window.electron.ipcRenderer.invoke('auth:getAllUsers')) as UserInfo[]
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
const result = await window.electron.auth.getAllUsers()
|
||||
return result.success && result.data ? result.data : []
|
||||
}, [])
|
||||
|
||||
const switchUser = useCallback(async (userInfo: UserInfo): Promise<boolean> => {
|
||||
setState((prev) => ({ ...prev, loading: true, error: null }))
|
||||
const result = await window.electron.auth.switchUser(userInfo)
|
||||
|
||||
try {
|
||||
const result = (await window.electron.ipcRenderer.invoke('auth:switchUser', userInfo)) as {
|
||||
success: boolean
|
||||
userInfo?: UserInfo
|
||||
error?: string
|
||||
}
|
||||
|
||||
if (result.success && result.userInfo) {
|
||||
setState({
|
||||
loading: false,
|
||||
user: result.userInfo,
|
||||
error: null,
|
||||
isAuthenticated: true
|
||||
})
|
||||
return true
|
||||
} else {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
loading: false,
|
||||
error: result.error || 'Switch user failed'
|
||||
}))
|
||||
return false
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Unknown error'
|
||||
setState((prev) => ({ ...prev, loading: false, error: message }))
|
||||
if (!result.success || !result.data?.userInfo) {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
loading: false,
|
||||
error: result.error || 'Switch user failed'
|
||||
}))
|
||||
return false
|
||||
}
|
||||
|
||||
setState({
|
||||
loading: false,
|
||||
user: result.data.userInfo,
|
||||
error: null,
|
||||
isAuthenticated: true
|
||||
})
|
||||
return true
|
||||
}, [])
|
||||
|
||||
const isAdmin = useCallback(async (): Promise<boolean> => {
|
||||
try {
|
||||
return (await window.electron.ipcRenderer.invoke('auth:isAdmin')) as boolean
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
const result = await window.electron.auth.isAdmin()
|
||||
return result.success && Boolean(result.data)
|
||||
}, [])
|
||||
|
||||
const reset = useCallback(() => {
|
||||
|
||||
@@ -85,8 +85,10 @@ export function useCleaner() {
|
||||
useEffect(() => {
|
||||
const initializePage = async () => {
|
||||
try {
|
||||
const admin = await window.electron.auth.isAdmin()
|
||||
const user = await window.electron.auth.getCurrentUser()
|
||||
const adminResult = await window.electron.auth.isAdmin()
|
||||
const userResult = await window.electron.auth.getCurrentUser()
|
||||
const admin = adminResult.success && Boolean(adminResult.data)
|
||||
const user = userResult.success ? userResult.data : undefined
|
||||
setIsAdmin(admin)
|
||||
if (user && user.userInfo) {
|
||||
setCurrentUsername(user.userInfo.username)
|
||||
@@ -98,13 +100,16 @@ export function useCleaner() {
|
||||
// Load managers
|
||||
if (admin) {
|
||||
const resp = await window.electron.materials.getManagers()
|
||||
setManagers(resp.managers)
|
||||
setSelectedManagers(new Set(resp.managers))
|
||||
const managersPayload = resp.success ? (resp.data as { managers: string[] } | undefined) : undefined
|
||||
const managerList = managersPayload?.managers ?? []
|
||||
setManagers(managerList)
|
||||
setSelectedManagers(new Set(managerList))
|
||||
}
|
||||
|
||||
// Get shared Production IDs
|
||||
const result = await window.electron.validation.getSharedProductionIds()
|
||||
setSharedProductionIdsCount(result.productionIds.length)
|
||||
const idsPayload = result.success ? (result.data as { productionIds?: string[] } | undefined) : undefined
|
||||
setSharedProductionIdsCount(idsPayload?.productionIds?.length ?? 0)
|
||||
} catch (err) {
|
||||
console.error('Initialization failed:', err)
|
||||
}
|
||||
@@ -159,21 +164,28 @@ export function useCleaner() {
|
||||
mode: valMode === 'full' ? 'database_full' : 'database_filtered',
|
||||
useSharedProductionIds: valMode === 'filtered'
|
||||
})
|
||||
const validationData = response.success ? (response.data as any) : null
|
||||
|
||||
if (response.success && response.results) {
|
||||
setValidationResults(response.results)
|
||||
const markedCodes = new Set(
|
||||
response.results.filter((r) => r.isMarkedForDeletion).map((r) => r.materialCode)
|
||||
if (response.success && validationData?.success && validationData.results) {
|
||||
setValidationResults(validationData.results)
|
||||
const markedCodes = new Set<string>(
|
||||
validationData.results
|
||||
.filter((r: ValidationResult) => r.isMarkedForDeletion)
|
||||
.map((r: ValidationResult) => r.materialCode)
|
||||
)
|
||||
setSelectedItems(markedCodes)
|
||||
|
||||
if (isAdmin) {
|
||||
const uniqueManagers = new Set(response.results.map((r) => r.managerName).filter(Boolean))
|
||||
setManagers([...uniqueManagers])
|
||||
const uniqueManagers = new Set<string>(
|
||||
validationData.results
|
||||
.map((r: ValidationResult) => r.managerName)
|
||||
.filter((name: string) => Boolean(name))
|
||||
)
|
||||
setManagers(Array.from(uniqueManagers))
|
||||
setSelectedManagers(uniqueManagers)
|
||||
}
|
||||
} else {
|
||||
alert(response.error || '校验失败')
|
||||
alert(response.error || validationData?.error || '校验失败')
|
||||
}
|
||||
} catch (err) {
|
||||
alert(err instanceof Error ? err.message : '校验过程中发生未知错误')
|
||||
@@ -285,14 +297,16 @@ export function useCleaner() {
|
||||
|
||||
if (materialsToUpsert.length > 0) {
|
||||
const res = await window.electron.materials.upsertBatch(materialsToUpsert)
|
||||
const payload = res.success ? (res.data as { stats?: { success?: number } } | undefined) : undefined
|
||||
if (!res.success) throw new Error(res.error || '写入物料失败')
|
||||
msgParts.push(`写入/更新成功:${res.stats?.success || 0} 条`)
|
||||
msgParts.push(`写入/更新成功:${payload?.stats?.success || 0} 条`)
|
||||
}
|
||||
|
||||
if (materialsToDelete.length > 0) {
|
||||
const res = await window.electron.materials.delete(materialsToDelete)
|
||||
const payload = res.success ? (res.data as { count?: number } | undefined) : undefined
|
||||
if (!res.success) throw new Error(res.error || '删除物料失败')
|
||||
msgParts.push(`删除成功:${res.count || 0} 条`)
|
||||
msgParts.push(`删除成功:${payload?.count || 0} 条`)
|
||||
}
|
||||
|
||||
alert(`操作完成!\n\n${msgParts.join('\n')}`)
|
||||
@@ -300,7 +314,8 @@ export function useCleaner() {
|
||||
// Reload managers if admin
|
||||
if (isAdmin) {
|
||||
const resp = await window.electron.materials.getManagers()
|
||||
setManagers(resp.managers)
|
||||
const payload = resp.success ? (resp.data as { managers?: string[] } | undefined) : undefined
|
||||
setManagers(payload?.managers ?? [])
|
||||
}
|
||||
} catch (err) {
|
||||
alert(err instanceof Error ? err.message : '操作失败')
|
||||
@@ -331,12 +346,13 @@ export function useCleaner() {
|
||||
|
||||
try {
|
||||
const cleanerDataResult = await window.electron.validation.getCleanerData()
|
||||
if (!cleanerDataResult.success) {
|
||||
const cleanerData = cleanerDataResult.success ? (cleanerDataResult.data as any) : null
|
||||
if (!cleanerDataResult.success || cleanerData?.success === false) {
|
||||
throw new Error(cleanerDataResult.error || '获取清理数据失败')
|
||||
}
|
||||
|
||||
const orderNumberList = cleanerDataResult.orderNumbers || []
|
||||
const materialCodeList = cleanerDataResult.materialCodes || []
|
||||
const orderNumberList = cleanerData?.orderNumbers || []
|
||||
const materialCodeList = cleanerData?.materialCodes || []
|
||||
|
||||
if (orderNumberList.length === 0)
|
||||
throw new Error('没有订单号数据。请先到数据提取页面输入 Production ID。')
|
||||
@@ -349,13 +365,14 @@ export function useCleaner() {
|
||||
dryRun,
|
||||
headless
|
||||
})
|
||||
const cleanerRunData = response.success ? (response.data as any) : null
|
||||
|
||||
if (response.success && response.data) {
|
||||
if (response.success && cleanerRunData) {
|
||||
setReportData({
|
||||
ordersProcessed: response.data.ordersProcessed,
|
||||
materialsDeleted: response.data.materialsDeleted,
|
||||
materialsSkipped: response.data.materialsSkipped,
|
||||
errors: response.data.errors
|
||||
ordersProcessed: cleanerRunData.ordersProcessed,
|
||||
materialsDeleted: cleanerRunData.materialsDeleted,
|
||||
materialsSkipped: cleanerRunData.materialsSkipped,
|
||||
errors: cleanerRunData.errors
|
||||
})
|
||||
} else {
|
||||
throw new Error(response.error || '清理失败')
|
||||
@@ -390,11 +407,12 @@ export function useCleaner() {
|
||||
}))
|
||||
|
||||
const response = await window.electron.cleaner.exportResults(exportItems)
|
||||
const exportData = response.success ? (response.data as any) : null
|
||||
|
||||
if (response.success) {
|
||||
alert(`导出成功!\n文件已保存到:${response.filePath}`)
|
||||
if (response.success && exportData?.success !== false) {
|
||||
alert(`导出成功!\n文件已保存到:${exportData?.filePath ?? ''}`)
|
||||
} else {
|
||||
throw new Error(response.error || '导出失败')
|
||||
throw new Error(response.error || exportData?.error || '导出失败')
|
||||
}
|
||||
} catch (err) {
|
||||
alert(err instanceof Error ? err.message : '导出过程中发生错误')
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
/**
|
||||
* IPC Hook for Validation operations
|
||||
*
|
||||
* Provides a React-friendly interface for validation IPC calls
|
||||
* with loading state, error handling, and data management.
|
||||
*/
|
||||
|
||||
import { useState, useCallback } from 'react'
|
||||
|
||||
// Types based on validation types
|
||||
interface ValidationRequest {
|
||||
mode: 'database_full' | 'database_filtered'
|
||||
productionIdFile?: string
|
||||
@@ -52,9 +44,6 @@ interface UseValidationReturn extends UseValidationState {
|
||||
reset: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for validation operations
|
||||
*/
|
||||
export function useValidation(): UseValidationReturn {
|
||||
const [state, setState] = useState<UseValidationState>({
|
||||
loading: false,
|
||||
@@ -63,82 +52,62 @@ export function useValidation(): UseValidationReturn {
|
||||
error: null
|
||||
})
|
||||
|
||||
const validate = useCallback(
|
||||
async (request: ValidationRequest): Promise<ValidationResponse | null> => {
|
||||
setState((prev) => ({ ...prev, loading: true, error: null }))
|
||||
const validate = useCallback(async (request: ValidationRequest): Promise<ValidationResponse | null> => {
|
||||
setState((prev) => ({ ...prev, loading: true, error: null }))
|
||||
const response = await window.electron.validation.validate(request)
|
||||
if (!response.success || !response.data) {
|
||||
setState((prev) => ({ ...prev, loading: false, error: response.error || 'Validation failed' }))
|
||||
return response.success ? null : { success: false, error: response.error }
|
||||
}
|
||||
|
||||
try {
|
||||
const result = (await window.electron.ipcRenderer.invoke(
|
||||
'validation:validate',
|
||||
request
|
||||
)) as ValidationResponse
|
||||
const result = response.data as ValidationResponse
|
||||
if (!result.success) {
|
||||
setState((prev) => ({ ...prev, loading: false, error: result.error || 'Validation failed' }))
|
||||
return result
|
||||
}
|
||||
|
||||
if (result.success) {
|
||||
const results = result.results || null
|
||||
const stats = result.stats || null
|
||||
setState({
|
||||
loading: false,
|
||||
data: results,
|
||||
stats: stats,
|
||||
error: null
|
||||
})
|
||||
return result
|
||||
} else {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
loading: false,
|
||||
error: result.error || 'Validation failed'
|
||||
}))
|
||||
return result
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Unknown error'
|
||||
setState((prev) => ({ ...prev, loading: false, error: message }))
|
||||
return null
|
||||
}
|
||||
},
|
||||
[]
|
||||
)
|
||||
setState({
|
||||
loading: false,
|
||||
data: result.results || null,
|
||||
stats: result.stats || null,
|
||||
error: null
|
||||
})
|
||||
return result
|
||||
}, [])
|
||||
|
||||
const setSharedProductionIds = useCallback(async (ids: string[]): Promise<void> => {
|
||||
try {
|
||||
await window.electron.ipcRenderer.invoke('validation:setSharedProductionIds', ids)
|
||||
} catch (error) {
|
||||
console.error('Failed to set shared production IDs:', error)
|
||||
}
|
||||
await window.electron.validation.setSharedProductionIds(ids)
|
||||
}, [])
|
||||
|
||||
const getSharedProductionIds = useCallback(async (): Promise<string[]> => {
|
||||
try {
|
||||
const result = (await window.electron.ipcRenderer.invoke(
|
||||
'validation:getSharedProductionIds'
|
||||
)) as { productionIds?: string[] }
|
||||
return result?.productionIds || []
|
||||
} catch {
|
||||
const result = await window.electron.validation.getSharedProductionIds()
|
||||
if (!result.success || !result.data) {
|
||||
return []
|
||||
}
|
||||
const payload = result.data as { productionIds?: string[] }
|
||||
return payload.productionIds || []
|
||||
}, [])
|
||||
|
||||
const getCleanerData = useCallback(async (): Promise<{
|
||||
orderNumbers: string[]
|
||||
materialCodes: string[]
|
||||
} | null> => {
|
||||
try {
|
||||
const result = (await window.electron.ipcRenderer.invoke('validation:getCleanerData')) as {
|
||||
success: boolean
|
||||
orderNumbers?: string[]
|
||||
materialCodes?: string[]
|
||||
}
|
||||
if (result.success) {
|
||||
return {
|
||||
orderNumbers: result.orderNumbers || [],
|
||||
materialCodes: result.materialCodes || []
|
||||
}
|
||||
}
|
||||
const getCleanerData = useCallback(async (): Promise<{ orderNumbers: string[]; materialCodes: string[] } | null> => {
|
||||
const result = await window.electron.validation.getCleanerData()
|
||||
if (!result.success || !result.data) {
|
||||
return null
|
||||
} catch {
|
||||
}
|
||||
|
||||
const payload = result.data as {
|
||||
success?: boolean
|
||||
orderNumbers?: string[]
|
||||
materialCodes?: string[]
|
||||
}
|
||||
|
||||
if (payload.success === false) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
orderNumbers: payload.orderNumbers || [],
|
||||
materialCodes: payload.materialCodes || []
|
||||
}
|
||||
}, [])
|
||||
|
||||
const reset = useCallback(() => {
|
||||
|
||||
@@ -26,14 +26,17 @@ const SettingsPage: React.FC = () => {
|
||||
try {
|
||||
setIsLoading(true)
|
||||
// ERP credentials are loaded from database (current user's config)
|
||||
const config = await window.electron.settings.getSettings()
|
||||
const response = await window.electron.settings.getSettings()
|
||||
const config = response.success ? (response.data as { erp?: ErpCredentials } | undefined) : undefined
|
||||
|
||||
// Extract ERP credentials from the config
|
||||
if (config && (config as any).erp) {
|
||||
if (config?.erp) {
|
||||
setCredentials({
|
||||
username: (config as any).erp.username || '',
|
||||
password: (config as any).erp.password || ''
|
||||
username: config.erp.username || '',
|
||||
password: config.erp.password || ''
|
||||
})
|
||||
} else if (!response.success) {
|
||||
showMessage('error', response.error || '加载 ERP 配置失败')
|
||||
}
|
||||
setIsModified(false)
|
||||
} catch (error) {
|
||||
@@ -56,13 +59,14 @@ const SettingsPage: React.FC = () => {
|
||||
username: credentials.username,
|
||||
password: credentials.password
|
||||
}
|
||||
} as any)
|
||||
})
|
||||
const saveData = result.success ? (result.data as { success?: boolean; error?: string } | undefined) : undefined
|
||||
|
||||
if (result.success) {
|
||||
if (result.success && saveData?.success !== false) {
|
||||
setIsModified(false)
|
||||
showMessage('success', 'ERP 账号密码保存成功')
|
||||
} else {
|
||||
showMessage('error', result.error || '保存失败')
|
||||
showMessage('error', result.error || saveData?.error || '保存失败')
|
||||
}
|
||||
} catch (error) {
|
||||
showMessage('error', '保存配置时发生错误')
|
||||
|
||||
Reference in New Issue
Block a user