feat: 添加设置页面,包含通用、安全、数据和关于选项卡,并支持偏好设置和账户管理。
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user