Files
accountbook/frontend/components/RecordModal.js
T
DeveloperandClaude Opus 4.6 b5f9a238bb feat: 删除亲情卡分类并优化搜索功能
- 移除亲情卡支出分类(前端+后端)
- 搜索结果添加点击编辑功能
- 提取 RecordModal 组件复用(index.js/search.js)
- 添加 useMemo 优化计算性能
- 优化类别查找为 O(1) 映射
- 添加删除分类接口输入验证

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 11:19:26 +08:00

147 lines
4.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Icon } from './icons';
export default function RecordModal({
isOpen,
onClose,
onSubmit,
onDelete,
formData,
setFormData,
formError,
submitting,
deleting,
editingRecord,
categories,
}) {
if (!isOpen) return null;
const handleTypeChange = (type) => {
setFormData({ ...formData, type, category: '' });
};
const isDisabled = submitting || deleting;
return (
<div className="modal-overlay modal-overlay--fullscreen" onClick={onClose}>
<div className="modal modal--fullscreen" onClick={(e) => e.stopPropagation()}>
<div className="modal-header">
<div>
<p className="eyebrow">{editingRecord ? '编辑记录' : '新增记录'}</p>
{editingRecord ? <h2>更新账目</h2> : null}
</div>
<button
type="button"
className="icon-button icon-button--ghost"
aria-label="关闭弹窗"
onClick={onClose}
disabled={isDisabled}
>
<Icon name="close" size={18} />
</button>
</div>
{formError && <div className="error-msg">{formError}</div>}
<form onSubmit={onSubmit}>
<div className="type-switch">
<button
type="button"
className={`type-btn expense ${formData.type === 'expense' ? 'active' : ''}`}
onClick={() => handleTypeChange('expense')}
disabled={isDisabled}
>
支出
</button>
<button
type="button"
className={`type-btn income ${formData.type === 'income' ? 'active' : ''}`}
onClick={() => handleTypeChange('income')}
disabled={isDisabled}
>
收入
</button>
</div>
<div className="form-group">
<label htmlFor="record-amount">金额</label>
<input
id="record-amount"
type="number"
className="amount-input"
value={formData.amount}
onChange={(e) => setFormData({ ...formData, amount: e.target.value })}
placeholder="0.00"
step="0.01"
required
disabled={isDisabled}
/>
</div>
<div className="form-group">
<label>分类</label>
<div className="category-grid">
{categories[formData.type].map((cat) => (
<button
key={cat.name}
type="button"
className={`category-btn ${formData.category === cat.name ? 'active' : ''}`}
onClick={() => setFormData({ ...formData, category: cat.name })}
disabled={isDisabled}
>
<span className="icon">{cat.icon}</span>
<span>{cat.name}</span>
</button>
))}
</div>
</div>
<div className="form-group">
<label>日期</label>
<div className="datetime-picker">
<input
type="date"
value={formData.date}
onChange={(e) => setFormData({ ...formData, date: e.target.value })}
required
disabled={isDisabled}
/>
<input
type="time"
value={formData.time || '00:00'}
onChange={(e) => setFormData({ ...formData, time: e.target.value })}
disabled={isDisabled}
/>
</div>
</div>
<div className="form-group">
<label htmlFor="record-note">备注可选</label>
<input
id="record-note"
type="text"
value={formData.note}
onChange={(e) => setFormData({ ...formData, note: e.target.value })}
placeholder="添加备注..."
disabled={isDisabled}
/>
</div>
<div className="modal-actions">
<button type="submit" className="btn btn-primary" disabled={isDisabled}>
{submitting ? (
<span className="button-content">
<Icon name="spinner" size={16} className="is-spinning" />
保存中...
</span>
) : '保存'}
</button>
{editingRecord && (
<button
type="button"
className="btn btn-danger"
onClick={onDelete}
disabled={isDisabled}
>
{deleting ? '删除中...' : '删除'}
</button>
)}
</div>
</form>
</div>
</div>
);
}