feat: 添加设置页面,采用玻璃拟态设计并支持分配规则管理
This commit is contained in:
@@ -37,6 +37,7 @@ export const AllocationRuleForm: React.FC<AllocationRuleFormProps> = ({
|
|||||||
triggerType: 'income',
|
triggerType: 'income',
|
||||||
sourceAccountId: undefined,
|
sourceAccountId: undefined,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
|
autoExecute: true,
|
||||||
targets: [],
|
targets: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -50,6 +51,7 @@ export const AllocationRuleForm: React.FC<AllocationRuleFormProps> = ({
|
|||||||
triggerType: allocationRule.triggerType as 'income' | 'manual',
|
triggerType: allocationRule.triggerType as 'income' | 'manual',
|
||||||
sourceAccountId: allocationRule.sourceAccountId,
|
sourceAccountId: allocationRule.sourceAccountId,
|
||||||
isActive: allocationRule.isActive,
|
isActive: allocationRule.isActive,
|
||||||
|
autoExecute: allocationRule.autoExecute,
|
||||||
targets: allocationRule.targets.map((target) => ({
|
targets: allocationRule.targets.map((target) => ({
|
||||||
targetType: target.targetType,
|
targetType: target.targetType,
|
||||||
targetId: target.targetId,
|
targetId: target.targetId,
|
||||||
@@ -309,6 +311,27 @@ export const AllocationRuleForm: React.FC<AllocationRuleFormProps> = ({
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</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 */}
|
{/* Allocation Targets */}
|
||||||
<div className="allocation-rule-form__section">
|
<div className="allocation-rule-form__section">
|
||||||
<div className="allocation-rule-form__section-header">
|
<div className="allocation-rule-form__section-header">
|
||||||
|
|||||||
@@ -706,3 +706,26 @@
|
|||||||
height: 20px;
|
height: 20px;
|
||||||
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3));
|
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);
|
||||||
|
}
|
||||||
@@ -439,6 +439,22 @@ function Settings() {
|
|||||||
<span className="settings-toggle-slider"></span>
|
<span className="settings-toggle-slider"></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ function transformAllocationRule(data: Record<string, unknown>): AllocationRule
|
|||||||
sourceAccountId: (data.source_account_id ?? data.sourceAccountId) as number | undefined,
|
sourceAccountId: (data.source_account_id ?? data.sourceAccountId) as number | undefined,
|
||||||
sourceAccount: data.source_account ? transformSourceAccount(data.source_account as Record<string, unknown>) : undefined,
|
sourceAccount: data.source_account ? transformSourceAccount(data.source_account as Record<string, unknown>) : undefined,
|
||||||
isActive: (data.is_active ?? data.isActive) as boolean,
|
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),
|
targets: ((data.targets as Record<string, unknown>[]) || []).map(transformAllocationTarget),
|
||||||
createdAt: (data.created_at ?? data.createdAt) as string,
|
createdAt: (data.created_at ?? data.createdAt) as string,
|
||||||
};
|
};
|
||||||
@@ -58,6 +59,7 @@ export interface AllocationRuleFormInput {
|
|||||||
triggerType: 'income' | 'manual';
|
triggerType: 'income' | 'manual';
|
||||||
sourceAccountId?: number;
|
sourceAccountId?: number;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
autoExecute?: boolean;
|
||||||
targets: AllocationTargetInput[];
|
targets: AllocationTargetInput[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +145,7 @@ export const createAllocationRule = async (
|
|||||||
trigger_type: data.triggerType,
|
trigger_type: data.triggerType,
|
||||||
source_account_id: data.sourceAccountId,
|
source_account_id: data.sourceAccountId,
|
||||||
is_active: data.isActive,
|
is_active: data.isActive,
|
||||||
|
auto_execute: data.autoExecute,
|
||||||
targets: data.targets.map(t => ({
|
targets: data.targets.map(t => ({
|
||||||
target_type: t.targetType,
|
target_type: t.targetType,
|
||||||
target_id: t.targetId,
|
target_id: t.targetId,
|
||||||
@@ -170,6 +173,7 @@ export const updateAllocationRule = async (
|
|||||||
trigger_type: data.triggerType,
|
trigger_type: data.triggerType,
|
||||||
source_account_id: data.sourceAccountId,
|
source_account_id: data.sourceAccountId,
|
||||||
is_active: data.isActive,
|
is_active: data.isActive,
|
||||||
|
auto_execute: data.autoExecute,
|
||||||
targets: data.targets.map(t => ({
|
targets: data.targets.map(t => ({
|
||||||
target_type: t.targetType,
|
target_type: t.targetType,
|
||||||
target_id: t.targetId,
|
target_id: t.targetId,
|
||||||
|
|||||||
@@ -76,7 +76,9 @@ export interface UserSettings {
|
|||||||
defaultExpenseAccountId?: number | null;
|
defaultExpenseAccountId?: number | null;
|
||||||
defaultIncomeAccountId?: number | null;
|
defaultIncomeAccountId?: number | null;
|
||||||
defaultExpenseAccount?: Account | null;
|
defaultExpenseAccount?: Account | null;
|
||||||
|
defaultExpenseAccount?: Account | null;
|
||||||
defaultIncomeAccount?: Account | null;
|
defaultIncomeAccount?: Account | null;
|
||||||
|
phone?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tag Interface
|
// Tag Interface
|
||||||
@@ -222,6 +224,7 @@ export interface AllocationRule {
|
|||||||
sourceAccountId?: number;
|
sourceAccountId?: number;
|
||||||
sourceAccount?: Account;
|
sourceAccount?: Account;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
autoExecute?: boolean;
|
||||||
targets: AllocationTarget[];
|
targets: AllocationTarget[];
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user