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 {
|
.accountLedgerSection {
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
|
|
|
||||||
|
|
@ -482,10 +482,57 @@ function FixedAccountsSection({ data }: { data: SystemAccountReportResponse['fix
|
||||||
* 区域账户汇总区域
|
* 区域账户汇总区域
|
||||||
* [2026-01-05] 更新:USDT改为绿积分
|
* [2026-01-05] 更新:USDT改为绿积分
|
||||||
* [2026-01-07] 更新:增加累计转出显示
|
* [2026-01-07] 更新:增加累计转出显示
|
||||||
|
* [2026-02-28] 更新:添加点击账户行展开分类账明细,显示来源账户和来源备注
|
||||||
*/
|
*/
|
||||||
function RegionAccountsSection({ data, type }: { data: RegionAccountsSummary; type: 'province' | 'city' }) {
|
function RegionAccountsSection({ data, type }: { data: RegionAccountsSummary; type: 'province' | 'city' }) {
|
||||||
const typeLabel = type === 'province' ? '省' : '市';
|
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 (
|
return (
|
||||||
<div className={styles.section}>
|
<div className={styles.section}>
|
||||||
<h3 className={styles.sectionTitle}>{typeLabel}区域账户汇总</h3>
|
<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>
|
||||||
<th>状态</th>
|
<th>状态</th>
|
||||||
|
<th>操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{data.accounts.map((account) => (
|
{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 解析区域代码为省市名称 */}
|
{/* [2026-01-07] 更新:使用 getAccountDisplayName 解析区域代码为省市名称 */}
|
||||||
<td>{account.regionCode ? getAccountDisplayName(account.regionCode) : '-'}</td>
|
<td>{account.regionCode ? getAccountDisplayName(account.regionCode) : '-'}</td>
|
||||||
<td>{formatAmount(account.usdtBalance)}</td>
|
<td>{formatAmount(account.usdtBalance)}</td>
|
||||||
|
|
@ -537,6 +589,15 @@ function RegionAccountsSection({ data, type }: { data: RegionAccountsSummary; ty
|
||||||
{account.status === 'ACTIVE' ? '正常' : account.status}
|
{account.status === 'ACTIVE' ? '正常' : account.status}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</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>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
@ -545,6 +606,66 @@ function RegionAccountsSection({ data, type }: { data: RegionAccountsSummary; ty
|
||||||
) : (
|
) : (
|
||||||
<div className={styles.emptyTable}>暂无{typeLabel}区域账户数据</div>
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue