import { useMemo, useState } from 'react'; import { Pressable, SafeAreaView, ScrollView, StyleSheet, Text, TextInput, View } from 'react-native'; import { StatusBar } from 'expo-status-bar'; import { classify, commitMobileTransaction, importStatement, parseLedger, type ImportedEvent, type Rule, validateTransaction } from './src/domain'; const sampleLedger = `option "operating_currency" "CNY" 2026-01-01 open Assets:Alipay CNY 2026-01-01 open Assets:WeChat CNY 2026-01-01 open Expenses:Food CNY 2026-01-01 open Expenses:Uncategorized CNY 2026-01-01 open Income:Uncategorized CNY include "mobile.bean" `; const sampleStatement = '交易时间,金额(元),收/支,交易对方,商品说明,交易订单号\n2026-07-01,24.50,支出,咖啡店,冰美式,ORDER-1\n2026-07-02,5000,收入,公司,工资,ORDER-2'; const rules: Rule[] = [{ id: 'coffee', priority: 100, channel: 'Alipay', counterpartyContains: '咖啡', channelAccount: 'Assets:Alipay', categoryAccount: 'Expenses:Food', narration: '咖啡', tags: ['food'], hits: 0 }]; type Tab = '账本' | '记账' | '导入' | '规则' | '诊断'; export default function App() { const ledger = useMemo(() => parseLedger([{ path: 'main.bean', content: sampleLedger }]), []); const [tab, setTab] = useState('账本'); const [mobileBean, setMobileBean] = useState(''); const [events, setEvents] = useState([]); const [message, setMessage] = useState('账本已解析。手机交易只会写入 mobile.bean。'); const [amount, setAmount] = useState(''); const [account, setAccount] = useState('Expenses:Food'); const addManual = () => { const draft = { date: '2026-07-10', narration: '手工记账', postings: [{ account: 'Assets:Alipay', amount: `-${amount}`, currency: 'CNY' }, { account, amount, currency: 'CNY' }] }; const result = validateTransaction(draft, ledger); if (!result.valid) return setMessage(result.errors.join(';')); try { const commit = commitMobileTransaction(draft, ledger, mobileBean); setMobileBean(commit.content); setAmount(''); setMessage('已追加到 mobile.bean。'); } catch (error) { setMessage(String(error)); } }; const loadDemo = () => { setEvents(importStatement(sampleStatement, 'alipay-csv-v1')); setMessage('已导入 2 条账单;请逐条确认。'); }; const confirm = (event: ImportedEvent) => { const candidate = classify(event, rules, ledger); try { const commit = commitMobileTransaction(candidate.draft, ledger, mobileBean); setMobileBean(commit.content); setEvents(current => current.filter(item => item.id !== event.id)); setMessage(candidate.ruleId ? '已按规则确认并写入 mobile.bean。' : '未匹配规则,已确认未分类分录。'); } catch (error) { setMessage(String(error)); } }; return Bean Mobile{message} {(['账本', '记账', '导入', '规则', '诊断'] as Tab[]).map(item => setTab(item)} style={[styles.tab, tab === item && styles.activeTab]}>{item})} {tab === '账本' && <>{ledger.accounts.size} 个已开户账户 · {ledger.transactions.length} 条桌面交易主文件只读;已配置 include "mobile.bean"。{mobileBean || '尚无手机端交易'}} {tab === '记账' &&