feat: 添加设置页面,包含通用、安全、数据和关于选项卡,并支持偏好设置和账户管理。

This commit is contained in:
2026-01-29 23:00:02 +08:00
parent 1713778845
commit e781525d65

View File

@@ -5,8 +5,10 @@ import AppLockSettings from '../../components/settings/AppLockSettings';
import { CapsuleSelector } from '../../components/common/CapsuleSelector/CapsuleSelector';
import { CustomSelect } from '../../components/common/CustomSelect/CustomSelect';
import { getSupportedCurrencies } from '../../services/exchangeRateService';
import { getSettings, updateSettings } from '../../services/settingsService';
import type { UserSettings } from '../../types';
import { getSupportedCurrencies } from '../../services/exchangeRateService';
import { getSettings, updateSettings, updateDefaultAccounts } from '../../services/settingsService';
import { getAccounts } from '../../services/accountService';
import type { UserSettings, Account } from '../../types';
import { Icon } from '@iconify/react';
import { ThemePicker } from '../../components/settings/ThemePicker/ThemePicker';
import './Settings.css';
@@ -38,6 +40,7 @@ function Settings() {
firstDayOfWeek: parseInt(localStorage.getItem('firstDayOfWeek') || '1'),
});
const [userSettings, setUserSettings] = useState<UserSettings | null>(null);
const [accounts, setAccounts] = useState<Account[]>([]);
const [saveMessage, setSaveMessage] = useState<string>('');
const currencies = getSupportedCurrencies();
@@ -45,6 +48,7 @@ function Settings() {
useEffect(() => {
// Load user settings
loadUserSettings();
loadAccounts();
// Sync settings state with global theme mode
setSettings(prev => ({ ...prev, theme: themeMode }));
}, [themeMode]);
@@ -58,6 +62,15 @@ function Settings() {
}
};
const loadAccounts = async () => {
try {
const data = await getAccounts();
setAccounts(data);
} catch (err) {
console.error('Failed to load accounts:', err);
}
};
const handleUserSettingChange = async (key: keyof UserSettings, value: any) => {
if (!userSettings) return;
@@ -74,6 +87,38 @@ function Settings() {
}
};
const handleDefaultAccountChange = async (key: 'defaultExpenseAccountId' | 'defaultIncomeAccountId', value: number) => {
if (!userSettings) return;
try {
const updateData = {
[key]: value
};
await updateDefaultAccounts(updateData);
// Update local state
let updatedSettings = { ...userSettings };
if (key === 'defaultExpenseAccountId') {
updatedSettings.defaultExpenseAccountId = value;
// Update the related object for immediate UI feedback if needed
const account = accounts.find(a => a.id === value);
if (account) updatedSettings.defaultExpenseAccount = account;
} else {
updatedSettings.defaultIncomeAccountId = value;
const account = accounts.find(a => a.id === value);
if (account) updatedSettings.defaultIncomeAccount = account;
}
setUserSettings(updatedSettings);
setSaveMessage('默认账户已更新');
setTimeout(() => setSaveMessage(''), 2000);
} catch (err) {
console.error('Failed to update default account:', err);
setSaveMessage('更新失败');
setTimeout(() => setSaveMessage(''), 2000);
}
};
@@ -276,6 +321,48 @@ function Settings() {
<div className="settings-group">
<h3></h3>
<div className="settings-item">
<div className="settings-item-info">
<label className="settings-item__label"></label>
<p className="settings-item__description">AI </p>
</div>
<CustomSelect
className="settings-custom-select"
value={userSettings?.defaultExpenseAccountId || ''}
onChange={(value) => handleDefaultAccountChange('defaultExpenseAccountId', Number(value))}
options={[
{ value: '', label: '不设置' },
...accounts
.filter(a => a.type !== 'credit_card' && a.type !== 'credit_line' ? true : true) // Show all for now, maybe filter logic later
.map(account => ({
value: account.id,
label: account.name
}))
]}
/>
</div>
<div className="settings-item">
<div className="settings-item-info">
<label className="settings-item__label"></label>
<p className="settings-item__description"></p>
</div>
<CustomSelect
className="settings-custom-select"
value={userSettings?.defaultIncomeAccountId || ''}
onChange={(value) => handleDefaultAccountChange('defaultIncomeAccountId', Number(value))}
options={[
{ value: '', label: '不设置' },
...accounts
//.filter(a => a.accountType === 'asset') // Typically income goes to assets
.map(account => ({
value: account.id,
label: account.name
}))
]}
/>
</div>
<div className="settings-item">
<div className="settings-item-info">
<label className="settings-item__label"></label>