refactor(admin-web): 固定账户明细改为在公共区域显示

将固定系统账户的分类账明细从每个卡片内部展开改为在卡片网格下方
的公共区域显示。点击任一账户的"查看明细"按钮,明细表格在下方
完整展示,提供更好的阅读体验。

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-01-06 22:58:30 -08:00
parent d6b3f04612
commit e1aec6c2c3
2 changed files with 131 additions and 54 deletions

View File

@ -620,6 +620,64 @@
opacity: 0.6; opacity: 0.6;
cursor: not-allowed; cursor: not-allowed;
} }
&Active {
background-color: #3b82f6;
color: #fff;
border-color: #3b82f6;
&:hover:not(:disabled) {
background-color: #2563eb;
border-color: #2563eb;
}
}
}
/* [2026-01-07] 新增:选中卡片样式 */
.accountCardSelected {
border-color: #3b82f6;
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
}
/* [2026-01-07] 更新:公共明细区域样式 */
.sharedLedgerSection {
margin-top: 24px;
padding: 20px;
background-color: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 8px;
}
.sharedLedgerHeader {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
padding-bottom: 12px;
border-bottom: 1px solid #e5e7eb;
}
.sharedLedgerTitle {
margin: 0;
font-size: 16px;
font-weight: 600;
color: #1f2937;
}
.closeLedgerButton {
padding: 6px 14px;
background-color: #fff;
color: #6b7280;
border: 1px solid #d1d5db;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
transition: all 0.2s ease;
&:hover {
background-color: #f3f4f6;
color: #374151;
}
} }
.accountLedgerSection { .accountLedgerSection {

View File

@ -296,7 +296,7 @@ export default function SystemAccountsTab() {
/** /**
* *
* [2026-01-05] USDT改为绿积分 * [2026-01-05] USDT改为绿积分
* [2026-01-07] * [2026-01-07]
*/ */
function FixedAccountsSection({ data }: { data: SystemAccountReportResponse['fixedAccounts'] }) { function FixedAccountsSection({ data }: { data: SystemAccountReportResponse['fixedAccounts'] }) {
// [2026-01-07] 更新:使用 SYSTEM_ACCOUNT_NAMES 映射获取正式名称 // [2026-01-07] 更新:使用 SYSTEM_ACCOUNT_NAMES 映射获取正式名称
@ -308,8 +308,8 @@ function FixedAccountsSection({ data }: { data: SystemAccountReportResponse['fix
{ key: 'platformFee', sequence: 'S0000000005', data: data.platformFee }, { key: 'platformFee', sequence: 'S0000000005', data: data.platformFee },
]; ];
// [2026-01-07] 新增:展开状态管理和分类账数据 // [2026-01-07] 新增:选中账户和分类账数据
const [expandedAccount, setExpandedAccount] = useState<string | null>(null); const [selectedAccount, setSelectedAccount] = useState<string | null>(null);
const [allLedgerData, setAllLedgerData] = useState<AllSystemAccountsLedgerResponse | null>(null); const [allLedgerData, setAllLedgerData] = useState<AllSystemAccountsLedgerResponse | null>(null);
const [ledgerLoading, setLedgerLoading] = useState(false); const [ledgerLoading, setLedgerLoading] = useState(false);
@ -319,7 +319,7 @@ function FixedAccountsSection({ data }: { data: SystemAccountReportResponse['fix
setLedgerLoading(true); setLedgerLoading(true);
try { try {
const response = await systemAccountReportService.getAllLedger({ pageSize: 50 }); const response = await systemAccountReportService.getAllLedger({ pageSize: 100 });
if (response.data) { if (response.data) {
setAllLedgerData(response.data); setAllLedgerData(response.data);
} }
@ -330,10 +330,10 @@ function FixedAccountsSection({ data }: { data: SystemAccountReportResponse['fix
} }
}, [allLedgerData]); }, [allLedgerData]);
// 切换显示某个账户的明细 // 选择账户查看明细
const handleToggleLedger = async (accountSequence: string) => { const handleSelectAccount = async (accountSequence: string) => {
if (expandedAccount === accountSequence) { if (selectedAccount === accountSequence) {
setExpandedAccount(null); setSelectedAccount(null);
return; return;
} }
@ -341,7 +341,7 @@ function FixedAccountsSection({ data }: { data: SystemAccountReportResponse['fix
if (!allLedgerData) { if (!allLedgerData) {
await loadAllLedger(); await loadAllLedger();
} }
setExpandedAccount(accountSequence); setSelectedAccount(accountSequence);
}; };
// 获取指定账户的分类账数据 // 获取指定账户的分类账数据
@ -353,16 +353,18 @@ function FixedAccountsSection({ data }: { data: SystemAccountReportResponse['fix
return accountLedger?.ledger || []; return accountLedger?.ledger || [];
}; };
// 当前选中账户的明细数据
const currentLedger = selectedAccount ? getAccountLedger(selectedAccount) : [];
return ( return (
<div className={styles.section}> <div className={styles.section}>
<h3 className={styles.sectionTitle}></h3> <h3 className={styles.sectionTitle}></h3>
<div className={styles.cardGrid}> <div className={styles.cardGrid}>
{accounts.map(({ key, sequence, data: accountData }) => { {accounts.map(({ key, sequence, data: accountData }) => {
const isExpanded = expandedAccount === sequence; const isSelected = selectedAccount === sequence;
const ledger = isExpanded ? getAccountLedger(sequence) : [];
return ( return (
<div key={key} className={styles.accountCard}> <div key={key} className={`${styles.accountCard} ${isSelected ? styles.accountCardSelected : ''}`}>
<div className={styles.cardHeader}> <div className={styles.cardHeader}>
<span className={styles.accountLabel}>{getAccountDisplayName(sequence)}</span> <span className={styles.accountLabel}>{getAccountDisplayName(sequence)}</span>
</div> </div>
@ -389,56 +391,73 @@ function FixedAccountsSection({ data }: { data: SystemAccountReportResponse['fix
{/* [2026-01-07] 新增:查看明细按钮 */} {/* [2026-01-07] 新增:查看明细按钮 */}
<div className={styles.cardFooter}> <div className={styles.cardFooter}>
<button <button
className={styles.viewLedgerButton} className={`${styles.viewLedgerButton} ${isSelected ? styles.viewLedgerButtonActive : ''}`}
onClick={() => handleToggleLedger(sequence)} onClick={() => handleSelectAccount(sequence)}
disabled={ledgerLoading} disabled={ledgerLoading}
> >
{ledgerLoading && !allLedgerData ? '加载中...' : isExpanded ? '收起明细' : '查看明细'} {ledgerLoading && !allLedgerData ? '加载中...' : isSelected ? '收起明细' : '查看明细'}
</button> </button>
</div> </div>
{/* [2026-01-07] 新增:展开的分类账明细 */}
{isExpanded && (
<div className={styles.accountLedgerSection}>
{ledger.length > 0 ? (
<div className={styles.tableWrapper}>
<table className={styles.table}>
<thead>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{ledger.map((entry) => (
<tr key={entry.id}>
<td>{new Date(entry.createdAt).toLocaleString('zh-CN')}</td>
<td>
<span className={styles.entryTypeBadge}>
{ENTRY_TYPE_LABELS[entry.entryType] || entry.entryType}
</span>
</td>
<td className={entry.amount >= 0 ? styles.amountPositive : styles.amountNegative}>
{entry.amount >= 0 ? '+' : ''}{formatAmount(entry.amount)} {getAssetTypeLabel(entry.assetType)}
</td>
<td>{entry.balanceAfter !== null ? formatAmount(entry.balanceAfter) : '-'}</td>
<td className={styles.memo}>{entry.memo || entry.allocationType || '-'}</td>
</tr>
))}
</tbody>
</table>
</div>
) : (
<div className={styles.emptyLedger}></div>
)}
</div>
)}
</div> </div>
); );
})} })}
</div> </div>
{/* [2026-01-07] 新增:在卡片下方的公共区域显示选中账户的完整明细 */}
{selectedAccount && (
<div className={styles.sharedLedgerSection}>
<div className={styles.sharedLedgerHeader}>
<h4 className={styles.sharedLedgerTitle}>
{getAccountDisplayName(selectedAccount)} -
</h4>
<button
className={styles.closeLedgerButton}
onClick={() => setSelectedAccount(null)}
>
</button>
</div>
{ledgerLoading ? (
<div className={styles.loading}>
<div className={styles.spinner} />
<span>...</span>
</div>
) : currentLedger.length > 0 ? (
<div className={styles.tableWrapper}>
<table className={styles.table}>
<thead>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{currentLedger.map((entry) => (
<tr key={entry.id}>
<td>{new Date(entry.createdAt).toLocaleString('zh-CN')}</td>
<td>
<span className={styles.entryTypeBadge}>
{ENTRY_TYPE_LABELS[entry.entryType] || entry.entryType}
</span>
</td>
<td className={entry.amount >= 0 ? styles.amountPositive : styles.amountNegative}>
{entry.amount >= 0 ? '+' : ''}{formatAmount(entry.amount)} {getAssetTypeLabel(entry.assetType)}
</td>
<td>{entry.balanceAfter !== null ? formatAmount(entry.balanceAfter) : '-'}</td>
<td className={styles.memo}>{entry.memo || entry.allocationType || '-'}</td>
</tr>
))}
</tbody>
</table>
</div>
) : (
<div className={styles.emptyLedger}></div>
)}
</div>
)}
</div> </div>
); );
} }