feat(admin-web): 省/市区域账户添加点击查看明细功能
RegionAccountsSection 新增: - 每行添加"查看明细"按钮,点击展开该账户分类账流水 - 明细表包含 时间/类型/金额/余额/来源账户/来源备注/备注 7列 - 复用 getAllLedger API 的 provinceAccountsLedger/cityAccountsLedger 数据 - 行点击和按钮点击均可展开/收起 - 新增 clickableRow/selectedRow CSS 样式 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
bf50810830
commit
6a659ca718
|
|
@ -683,6 +683,22 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* [2026-02-28] 新增:区域账户表格行可点击样式 */
|
||||
.clickableRow {
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
background-color: #eff6ff !important;
|
||||
}
|
||||
}
|
||||
|
||||
.selectedRow {
|
||||
cursor: pointer;
|
||||
background-color: #eff6ff !important;
|
||||
border-left: 3px solid #3b82f6;
|
||||
}
|
||||
|
||||
.accountLedgerSection {
|
||||
margin-top: 12px;
|
||||
padding-top: 12px;
|
||||
|
|
|
|||
|
|
@ -482,10 +482,57 @@ function FixedAccountsSection({ data }: { data: SystemAccountReportResponse['fix
|
|||
* 区域账户汇总区域
|
||||
* [2026-01-05] 更新:USDT改为绿积分
|
||||
* [2026-01-07] 更新:增加累计转出显示
|
||||
* [2026-02-28] 更新:添加点击账户行展开分类账明细,显示来源账户和来源备注
|
||||
*/
|
||||
function RegionAccountsSection({ data, type }: { data: RegionAccountsSummary; type: 'province' | 'city' }) {
|
||||
const typeLabel = type === 'province' ? '省' : '市';
|
||||
|
||||
// [2026-02-28] 新增:账户明细展开相关状态
|
||||
const [selectedAccount, setSelectedAccount] = useState<string | null>(null);
|
||||
const [allLedgerData, setAllLedgerData] = useState<AllSystemAccountsLedgerResponse | null>(null);
|
||||
const [ledgerLoading, setLedgerLoading] = useState(false);
|
||||
|
||||
// 加载所有系统账户分类账数据
|
||||
const loadAllLedger = useCallback(async () => {
|
||||
if (allLedgerData) return;
|
||||
setLedgerLoading(true);
|
||||
try {
|
||||
const response = await systemAccountReportService.getAllLedger({ pageSize: 100 });
|
||||
if (response.data) {
|
||||
setAllLedgerData(response.data);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Failed to load ledger data:', err);
|
||||
} finally {
|
||||
setLedgerLoading(false);
|
||||
}
|
||||
}, [allLedgerData]);
|
||||
|
||||
// 获取指定区域账户的分类账数据
|
||||
const getAccountLedger = useCallback((accountSequence: string): LedgerEntryDTO[] => {
|
||||
const ledgerKey = type === 'province' ? 'provinceAccountsLedger' : 'cityAccountsLedger';
|
||||
const regionLedgers = allLedgerData?.[ledgerKey];
|
||||
if (!regionLedgers) return [];
|
||||
const accountLedger = regionLedgers.find(
|
||||
(item) => item.accountSequence === accountSequence
|
||||
);
|
||||
return accountLedger?.ledger || [];
|
||||
}, [allLedgerData, type]);
|
||||
|
||||
// 点击账户行展开/收起明细
|
||||
const handleSelectAccount = async (accountSequence: string) => {
|
||||
if (selectedAccount === accountSequence) {
|
||||
setSelectedAccount(null);
|
||||
return;
|
||||
}
|
||||
if (!allLedgerData) {
|
||||
await loadAllLedger();
|
||||
}
|
||||
setSelectedAccount(accountSequence);
|
||||
};
|
||||
|
||||
const currentLedger = selectedAccount ? getAccountLedger(selectedAccount) : [];
|
||||
|
||||
return (
|
||||
<div className={styles.section}>
|
||||
<h3 className={styles.sectionTitle}>{typeLabel}区域账户汇总</h3>
|
||||
|
|
@ -522,11 +569,16 @@ function RegionAccountsSection({ data, type }: { data: RegionAccountsSummary; ty
|
|||
<th>累计收入 (绿积分)</th>
|
||||
<th>累计转出 (绿积分)</th>
|
||||
<th>状态</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.accounts.map((account) => (
|
||||
<tr key={account.id}>
|
||||
<tr
|
||||
key={account.id}
|
||||
className={selectedAccount === account.accountSequence ? styles.selectedRow : styles.clickableRow}
|
||||
onClick={() => handleSelectAccount(account.accountSequence)}
|
||||
>
|
||||
{/* [2026-01-07] 更新:使用 getAccountDisplayName 解析区域代码为省市名称 */}
|
||||
<td>{account.regionCode ? getAccountDisplayName(account.regionCode) : '-'}</td>
|
||||
<td>{formatAmount(account.usdtBalance)}</td>
|
||||
|
|
@ -537,6 +589,15 @@ function RegionAccountsSection({ data, type }: { data: RegionAccountsSummary; ty
|
|||
{account.status === 'ACTIVE' ? '正常' : account.status}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<button
|
||||
className={`${styles.viewLedgerButton} ${selectedAccount === account.accountSequence ? styles.viewLedgerButtonActive : ''}`}
|
||||
onClick={(e) => { e.stopPropagation(); handleSelectAccount(account.accountSequence); }}
|
||||
disabled={ledgerLoading}
|
||||
>
|
||||
{ledgerLoading && !allLedgerData ? '加载中...' : selectedAccount === account.accountSequence ? '收起明细' : '查看明细'}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
|
|
@ -545,6 +606,66 @@ function RegionAccountsSection({ data, type }: { data: RegionAccountsSummary; ty
|
|||
) : (
|
||||
<div className={styles.emptyTable}>暂无{typeLabel}区域账户数据</div>
|
||||
)}
|
||||
|
||||
{/* [2026-02-28] 新增:选中账户的分类账明细展开区域 */}
|
||||
{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>
|
||||
<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.sourceAccount}>{entry.sourceAccountSequence || '-'}</td>
|
||||
<td className={styles.memo}>{entry.sourceMemo || '-'}</td>
|
||||
<td className={styles.memo}>{entry.memo || entry.allocationType || '-'}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
) : (
|
||||
<div className={styles.emptyLedger}>暂无流水记录</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue