feat: 添加设置页面,采用玻璃拟态设计并支持分配规则管理

This commit is contained in:
2026-02-02 01:41:36 +08:00
parent ad7676753c
commit ddb35ebb32
5 changed files with 69 additions and 0 deletions

View File

@@ -37,6 +37,7 @@ export const AllocationRuleForm: React.FC<AllocationRuleFormProps> = ({
triggerType: 'income',
sourceAccountId: undefined,
isActive: true,
autoExecute: true,
targets: [],
});
@@ -50,6 +51,7 @@ export const AllocationRuleForm: React.FC<AllocationRuleFormProps> = ({
triggerType: allocationRule.triggerType as 'income' | 'manual',
sourceAccountId: allocationRule.sourceAccountId,
isActive: allocationRule.isActive,
autoExecute: allocationRule.autoExecute,
targets: allocationRule.targets.map((target) => ({
targetType: target.targetType,
targetId: target.targetId,
@@ -309,6 +311,27 @@ export const AllocationRuleForm: React.FC<AllocationRuleFormProps> = ({
</label>
</div>
{/* Auto Execute */}
<div className="allocation-rule-form__field allocation-rule-form__field--checkbox">
<label className="allocation-rule-form__checkbox-label">
<input
type="checkbox"
name="autoExecute"
checked={formData.autoExecute !== false}
onChange={(e) => {
const checked = e.target.checked;
setFormData((prev) => ({
...prev,
autoExecute: checked,
}));
}}
className="allocation-rule-form__checkbox"
disabled={isLoading}
/>
<span></span>
</label>
</div>
{/* Allocation Targets */}
<div className="allocation-rule-form__section">
<div className="allocation-rule-form__section-header">

View File

@@ -706,3 +706,26 @@
height: 20px;
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3));
}
.settings-input-container {
min-width: 200px;
max-width: 50%;
}
.settings-text-input {
width: 100%;
padding: var(--spacing-md);
border: 1px solid var(--glass-border);
border-radius: var(--radius-lg);
background: var(--glass-bg);
color: var(--color-text);
font-size: var(--font-base);
transition: all 0.2s ease;
}
.settings-text-input:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px var(--color-primary-lighter);
background: rgba(255, 255, 255, 0.9);
}

View File

@@ -439,6 +439,22 @@ function Settings() {
<span className="settings-toggle-slider"></span>
</label>
</div>
<div className="settings-item">
<div className="settings-item-info">
<label className="settings-item__label"></label>
<p className="settings-item__description"></p>
</div>
<div className="settings-input-container">
<input
type="tel"
className="settings-text-input"
placeholder="请输入手机号"
value={userSettings?.phone || ''}
onChange={(e) => handleUserSettingChange('phone', e.target.value)}
/>
</div>
</div>
</div>
</div>
</section>

View File

@@ -17,6 +17,7 @@ function transformAllocationRule(data: Record<string, unknown>): AllocationRule
sourceAccountId: (data.source_account_id ?? data.sourceAccountId) as number | undefined,
sourceAccount: data.source_account ? transformSourceAccount(data.source_account as Record<string, unknown>) : undefined,
isActive: (data.is_active ?? data.isActive) as boolean,
autoExecute: (data.auto_execute ?? data.autoExecute) as boolean | undefined,
targets: ((data.targets as Record<string, unknown>[]) || []).map(transformAllocationTarget),
createdAt: (data.created_at ?? data.createdAt) as string,
};
@@ -58,6 +59,7 @@ export interface AllocationRuleFormInput {
triggerType: 'income' | 'manual';
sourceAccountId?: number;
isActive: boolean;
autoExecute?: boolean;
targets: AllocationTargetInput[];
}
@@ -143,6 +145,7 @@ export const createAllocationRule = async (
trigger_type: data.triggerType,
source_account_id: data.sourceAccountId,
is_active: data.isActive,
auto_execute: data.autoExecute,
targets: data.targets.map(t => ({
target_type: t.targetType,
target_id: t.targetId,
@@ -170,6 +173,7 @@ export const updateAllocationRule = async (
trigger_type: data.triggerType,
source_account_id: data.sourceAccountId,
is_active: data.isActive,
auto_execute: data.autoExecute,
targets: data.targets.map(t => ({
target_type: t.targetType,
target_id: t.targetId,

View File

@@ -76,7 +76,9 @@ export interface UserSettings {
defaultExpenseAccountId?: number | null;
defaultIncomeAccountId?: number | null;
defaultExpenseAccount?: Account | null;
defaultExpenseAccount?: Account | null;
defaultIncomeAccount?: Account | null;
phone?: string;
}
// Tag Interface
@@ -222,6 +224,7 @@ export interface AllocationRule {
sourceAccountId?: number;
sourceAccount?: Account;
isActive: boolean;
autoExecute?: boolean;
targets: AllocationTarget[];
createdAt: string;
}