feat(admin-web): add system account transfer management page
- Add system-transfer page with transfer form and order history - Add SystemWithdrawalService for API calls - Add useSystemWithdrawal hooks for React Query integration - Add system-withdrawal types definitions - Add navigation menu item for system transfer 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
fe8e9a9bb6
commit
b947fe8205
|
|
@ -0,0 +1,690 @@
|
|||
'use client';
|
||||
|
||||
import { useState, useCallback } from 'react';
|
||||
import { Modal, toast, Button } from '@/components/common';
|
||||
import { PageContainer } from '@/components/layout';
|
||||
import { cn } from '@/utils/helpers';
|
||||
import { formatDateTime } from '@/utils/formatters';
|
||||
import {
|
||||
useSystemWithdrawalAccounts,
|
||||
useSystemWithdrawalOrders,
|
||||
useRequestSystemWithdrawal,
|
||||
} from '@/hooks/useSystemWithdrawal';
|
||||
import {
|
||||
SystemWithdrawalOrder,
|
||||
SystemWithdrawalStatus,
|
||||
SystemAccount,
|
||||
getSystemWithdrawalStatusInfo,
|
||||
} from '@/types/system-withdrawal.types';
|
||||
import styles from './system-transfer.module.scss';
|
||||
|
||||
type TabType = 'transfer' | 'orders';
|
||||
|
||||
/**
|
||||
* 系统账户划转管理页面
|
||||
*/
|
||||
export default function SystemTransferPage() {
|
||||
// 当前标签页
|
||||
const [activeTab, setActiveTab] = useState<TabType>('transfer');
|
||||
|
||||
// 筛选状态
|
||||
const [filters, setFilters] = useState({
|
||||
fromAccountSequence: '',
|
||||
toAccountSequence: '',
|
||||
status: '' as SystemWithdrawalStatus | '',
|
||||
page: 1,
|
||||
limit: 20,
|
||||
});
|
||||
|
||||
// 表单状态
|
||||
const [selectedAccount, setSelectedAccount] = useState<SystemAccount | null>(null);
|
||||
const [transferForm, setTransferForm] = useState({
|
||||
toAccountSequence: '',
|
||||
amount: '',
|
||||
memo: '',
|
||||
});
|
||||
const [formErrors, setFormErrors] = useState<Record<string, string>>({});
|
||||
|
||||
// 弹窗状态
|
||||
const [viewingOrder, setViewingOrder] = useState<SystemWithdrawalOrder | null>(null);
|
||||
const [confirmModalOpen, setConfirmModalOpen] = useState(false);
|
||||
|
||||
// 数据查询
|
||||
const accountsQuery = useSystemWithdrawalAccounts();
|
||||
const ordersQuery = useSystemWithdrawalOrders({
|
||||
fromAccountSequence: filters.fromAccountSequence || undefined,
|
||||
toAccountSequence: filters.toAccountSequence || undefined,
|
||||
status: filters.status || undefined,
|
||||
page: filters.page,
|
||||
limit: filters.limit,
|
||||
});
|
||||
|
||||
// Mutations
|
||||
const requestMutation = useRequestSystemWithdrawal();
|
||||
|
||||
// 表单验证
|
||||
const validateForm = (): boolean => {
|
||||
const errors: Record<string, string> = {};
|
||||
|
||||
if (!selectedAccount) {
|
||||
errors.fromAccount = '请选择源账户';
|
||||
}
|
||||
|
||||
if (!transferForm.toAccountSequence) {
|
||||
errors.toAccountSequence = '请输入目标账户序列号';
|
||||
} else if (!/^D\d{11}$/.test(transferForm.toAccountSequence)) {
|
||||
errors.toAccountSequence = '账户序列号格式不正确,应为 D + 11位数字';
|
||||
}
|
||||
|
||||
if (!transferForm.amount) {
|
||||
errors.amount = '请输入划转金额';
|
||||
} else {
|
||||
const amount = parseFloat(transferForm.amount);
|
||||
if (isNaN(amount) || amount <= 0) {
|
||||
errors.amount = '请输入有效的金额';
|
||||
} else if (amount < 1) {
|
||||
errors.amount = '最小划转金额为 1 USDT';
|
||||
}
|
||||
}
|
||||
|
||||
setFormErrors(errors);
|
||||
return Object.keys(errors).length === 0;
|
||||
};
|
||||
|
||||
// 提交划转请求
|
||||
const handleSubmitTransfer = async () => {
|
||||
if (!validateForm() || !selectedAccount) return;
|
||||
|
||||
try {
|
||||
await requestMutation.mutateAsync({
|
||||
fromAccountSequence: selectedAccount.accountSequence,
|
||||
toAccountSequence: transferForm.toAccountSequence,
|
||||
amount: transferForm.amount,
|
||||
memo: transferForm.memo || undefined,
|
||||
});
|
||||
toast.success('划转请求已提交,等待区块链确认');
|
||||
setConfirmModalOpen(false);
|
||||
// 重置表单
|
||||
setSelectedAccount(null);
|
||||
setTransferForm({ toAccountSequence: '', amount: '', memo: '' });
|
||||
setFormErrors({});
|
||||
// 切换到订单列表查看
|
||||
setActiveTab('orders');
|
||||
} catch (err) {
|
||||
toast.error((err as Error).message || '划转失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 打开确认弹窗
|
||||
const handleOpenConfirm = () => {
|
||||
if (validateForm()) {
|
||||
setConfirmModalOpen(true);
|
||||
}
|
||||
};
|
||||
|
||||
// 搜索
|
||||
const handleSearch = useCallback(() => {
|
||||
setFilters((prev) => ({ ...prev, page: 1 }));
|
||||
}, []);
|
||||
|
||||
// 翻页
|
||||
const handlePageChange = (page: number) => {
|
||||
setFilters((prev) => ({ ...prev, page }));
|
||||
};
|
||||
|
||||
// 渲染账户选择卡片
|
||||
const renderAccountCards = () => {
|
||||
if (accountsQuery.isLoading) {
|
||||
return <div className={styles.systemTransfer__loading}>加载账户列表...</div>;
|
||||
}
|
||||
|
||||
if (accountsQuery.error) {
|
||||
return (
|
||||
<div className={styles.systemTransfer__error}>
|
||||
<span>{(accountsQuery.error as Error).message || '加载失败'}</span>
|
||||
<Button variant="outline" size="sm" onClick={() => accountsQuery.refetch()}>
|
||||
重试
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const accounts = accountsQuery.data || [];
|
||||
if (accounts.length === 0) {
|
||||
return <div className={styles.systemTransfer__empty}>暂无可划转账户</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.systemTransfer__accountCards}>
|
||||
{accounts.map((account) => (
|
||||
<div
|
||||
key={account.accountSequence}
|
||||
className={cn(
|
||||
styles.systemTransfer__accountCard,
|
||||
selectedAccount?.accountSequence === account.accountSequence &&
|
||||
styles['systemTransfer__accountCard--selected']
|
||||
)}
|
||||
onClick={() => setSelectedAccount(account)}
|
||||
>
|
||||
<div className={styles.systemTransfer__accountCardName}>{account.name}</div>
|
||||
<div className={styles.systemTransfer__accountCardSequence}>{account.accountSequence}</div>
|
||||
{account.balance && (
|
||||
<div className={styles.systemTransfer__accountCardBalance}>
|
||||
余额: {parseFloat(account.balance).toFixed(2)} USDT
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// 渲染划转表单
|
||||
const renderTransferForm = () => {
|
||||
return (
|
||||
<>
|
||||
<div className={styles.systemTransfer__warning}>
|
||||
从系统账户划转资金到用户账户,资金将通过区块链转账,完成后会自动记录分类账。
|
||||
</div>
|
||||
|
||||
<h3 style={{ marginBottom: '16px', fontSize: '16px' }}>1. 选择源账户</h3>
|
||||
{renderAccountCards()}
|
||||
{formErrors.fromAccount && (
|
||||
<div className={styles.systemTransfer__formError}>{formErrors.fromAccount}</div>
|
||||
)}
|
||||
|
||||
<h3 style={{ marginBottom: '16px', fontSize: '16px' }}>2. 填写划转信息</h3>
|
||||
<div className={styles.systemTransfer__form}>
|
||||
<div className={styles.systemTransfer__formGroup}>
|
||||
<label>目标账户序列号 *</label>
|
||||
<input
|
||||
type="text"
|
||||
value={transferForm.toAccountSequence}
|
||||
onChange={(e) => {
|
||||
setTransferForm({ ...transferForm, toAccountSequence: e.target.value });
|
||||
setFormErrors({ ...formErrors, toAccountSequence: '' });
|
||||
}}
|
||||
placeholder="例如:D25121400005"
|
||||
/>
|
||||
<div className={styles.systemTransfer__formHint}>输入用户的账户序列号(D开头+11位数字)</div>
|
||||
{formErrors.toAccountSequence && (
|
||||
<div className={styles.systemTransfer__formError}>{formErrors.toAccountSequence}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles.systemTransfer__formGroup}>
|
||||
<label>划转金额 (USDT) *</label>
|
||||
<input
|
||||
type="number"
|
||||
value={transferForm.amount}
|
||||
onChange={(e) => {
|
||||
setTransferForm({ ...transferForm, amount: e.target.value });
|
||||
setFormErrors({ ...formErrors, amount: '' });
|
||||
}}
|
||||
placeholder="例如:100"
|
||||
min="1"
|
||||
step="0.01"
|
||||
/>
|
||||
<div className={styles.systemTransfer__formHint}>最小划转金额为 1 USDT</div>
|
||||
{formErrors.amount && (
|
||||
<div className={styles.systemTransfer__formError}>{formErrors.amount}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles.systemTransfer__formGroup}>
|
||||
<label>备注 (可选)</label>
|
||||
<textarea
|
||||
value={transferForm.memo}
|
||||
onChange={(e) => setTransferForm({ ...transferForm, memo: e.target.value })}
|
||||
placeholder="请输入划转备注..."
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: '16px' }}>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={handleOpenConfirm}
|
||||
disabled={!selectedAccount || !transferForm.toAccountSequence || !transferForm.amount}
|
||||
>
|
||||
提交划转
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// 渲染订单列表
|
||||
const renderOrderList = () => {
|
||||
const { data, isLoading, error, refetch } = ordersQuery;
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* 筛选区域 */}
|
||||
<div className={styles.systemTransfer__filters}>
|
||||
<input
|
||||
type="text"
|
||||
className={styles.systemTransfer__input}
|
||||
placeholder="源账户"
|
||||
value={filters.fromAccountSequence}
|
||||
onChange={(e) => setFilters({ ...filters, fromAccountSequence: e.target.value })}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
className={styles.systemTransfer__input}
|
||||
placeholder="目标账户"
|
||||
value={filters.toAccountSequence}
|
||||
onChange={(e) => setFilters({ ...filters, toAccountSequence: e.target.value })}
|
||||
/>
|
||||
<select
|
||||
className={styles.systemTransfer__select}
|
||||
value={filters.status}
|
||||
onChange={(e) =>
|
||||
setFilters({ ...filters, status: e.target.value as SystemWithdrawalStatus | '' })
|
||||
}
|
||||
>
|
||||
<option value="">全部状态</option>
|
||||
<option value="PENDING">待处理</option>
|
||||
<option value="FROZEN">已冻结</option>
|
||||
<option value="BROADCASTED">已广播</option>
|
||||
<option value="CONFIRMED">已确认</option>
|
||||
<option value="FAILED">失败</option>
|
||||
</select>
|
||||
<Button variant="outline" size="sm" onClick={handleSearch}>
|
||||
搜索
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" onClick={() => refetch()}>
|
||||
刷新
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 列表 */}
|
||||
<div className={styles.systemTransfer__list}>
|
||||
{isLoading ? (
|
||||
<div className={styles.systemTransfer__loading}>加载中...</div>
|
||||
) : error ? (
|
||||
<div className={styles.systemTransfer__error}>
|
||||
<span>{(error as Error).message || '加载失败'}</span>
|
||||
<Button variant="outline" size="sm" onClick={() => refetch()}>
|
||||
重试
|
||||
</Button>
|
||||
</div>
|
||||
) : !data || data.items.length === 0 ? (
|
||||
<div className={styles.systemTransfer__empty}>暂无数据</div>
|
||||
) : (
|
||||
<>
|
||||
{/* 表格 */}
|
||||
<table className={styles.systemTransfer__table}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>订单号</th>
|
||||
<th>源账户</th>
|
||||
<th>目标账户</th>
|
||||
<th>金额</th>
|
||||
<th>状态</th>
|
||||
<th>TxHash</th>
|
||||
<th>创建时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.items.map((order) => {
|
||||
const statusInfo = getSystemWithdrawalStatusInfo(order.status);
|
||||
return (
|
||||
<tr key={order.orderNo}>
|
||||
<td>
|
||||
<div className={styles.systemTransfer__orderNo}>{order.orderNo}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div className={styles.systemTransfer__accountSequence}>
|
||||
{order.fromAccountSequence}
|
||||
</div>
|
||||
<div className={styles.systemTransfer__accountName}>
|
||||
{order.fromAccountName}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div className={styles.systemTransfer__accountSequence}>
|
||||
{order.toAccountSequence}
|
||||
</div>
|
||||
{order.toUserName && (
|
||||
<div className={styles.systemTransfer__accountName}>
|
||||
{order.toUserName}
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
<td>
|
||||
<div className={styles.systemTransfer__amount}>
|
||||
{parseFloat(order.amount).toFixed(2)} USDT
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span
|
||||
className={styles.systemTransfer__statusTag}
|
||||
style={{ backgroundColor: statusInfo.color, color: 'white' }}
|
||||
>
|
||||
{statusInfo.label}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
{order.txHash ? (
|
||||
<div className={styles.systemTransfer__txHash} title={order.txHash}>
|
||||
{order.txHash.slice(0, 10)}...
|
||||
</div>
|
||||
) : (
|
||||
<span style={{ color: '#999' }}>-</span>
|
||||
)}
|
||||
</td>
|
||||
<td>{formatDateTime(order.createdAt)}</td>
|
||||
<td>
|
||||
<div className={styles.systemTransfer__actions}>
|
||||
<button
|
||||
className={styles.systemTransfer__actionBtn}
|
||||
onClick={() => setViewingOrder(order)}
|
||||
>
|
||||
查看
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{/* 分页 */}
|
||||
{data.total > filters.limit && (
|
||||
<div className={styles.systemTransfer__pagination}>
|
||||
<span>
|
||||
共 {data.total} 条,第 {data.page} / {Math.ceil(data.total / data.limit)} 页
|
||||
</span>
|
||||
<div className={styles.systemTransfer__pageButtons}>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={data.page <= 1}
|
||||
onClick={() => handlePageChange(data.page - 1)}
|
||||
>
|
||||
上一页
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={data.page >= Math.ceil(data.total / data.limit)}
|
||||
onClick={() => handlePageChange(data.page + 1)}
|
||||
>
|
||||
下一页
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<PageContainer title="系统划转">
|
||||
<div className={styles.systemTransfer}>
|
||||
{/* 页面标题 */}
|
||||
<div className={styles.systemTransfer__header}>
|
||||
<h1 className={styles.systemTransfer__title}>系统账户划转</h1>
|
||||
<p className={styles.systemTransfer__subtitle}>
|
||||
从系统账户(总部、运营、积分股池等)划转资金到用户账户
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 主内容卡片 */}
|
||||
<div className={styles.systemTransfer__card}>
|
||||
{/* 标签页 */}
|
||||
<div className={styles.systemTransfer__tabs}>
|
||||
<button
|
||||
className={cn(
|
||||
styles.systemTransfer__tab,
|
||||
activeTab === 'transfer' && styles['systemTransfer__tab--active']
|
||||
)}
|
||||
onClick={() => setActiveTab('transfer')}
|
||||
>
|
||||
发起划转
|
||||
</button>
|
||||
<button
|
||||
className={cn(
|
||||
styles.systemTransfer__tab,
|
||||
activeTab === 'orders' && styles['systemTransfer__tab--active']
|
||||
)}
|
||||
onClick={() => setActiveTab('orders')}
|
||||
>
|
||||
划转记录
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 内容区域 */}
|
||||
{activeTab === 'transfer' ? renderTransferForm() : renderOrderList()}
|
||||
</div>
|
||||
|
||||
{/* 查看详情弹窗 */}
|
||||
<Modal
|
||||
visible={!!viewingOrder}
|
||||
title="划转订单详情"
|
||||
onClose={() => setViewingOrder(null)}
|
||||
footer={
|
||||
<div className={styles.systemTransfer__modalFooter}>
|
||||
<Button variant="outline" onClick={() => setViewingOrder(null)}>
|
||||
关闭
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
width={600}
|
||||
>
|
||||
{viewingOrder && (
|
||||
<div className={styles.systemTransfer__detail}>
|
||||
<div className={styles.systemTransfer__detailSection}>
|
||||
<div className={styles.systemTransfer__detailTitle}>订单信息</div>
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>订单号:</span>
|
||||
<span className={styles.systemTransfer__detailValue}>{viewingOrder.orderNo}</span>
|
||||
</div>
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>金额:</span>
|
||||
<span className={styles.systemTransfer__detailValue}>
|
||||
{parseFloat(viewingOrder.amount).toFixed(2)} USDT
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>状态:</span>
|
||||
<span
|
||||
className={styles.systemTransfer__statusTag}
|
||||
style={{
|
||||
backgroundColor: getSystemWithdrawalStatusInfo(viewingOrder.status).color,
|
||||
color: 'white',
|
||||
}}
|
||||
>
|
||||
{getSystemWithdrawalStatusInfo(viewingOrder.status).label}
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>创建时间:</span>
|
||||
<span className={styles.systemTransfer__detailValue}>
|
||||
{formatDateTime(viewingOrder.createdAt)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.systemTransfer__detailSection}>
|
||||
<div className={styles.systemTransfer__detailTitle}>源账户</div>
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>账户序列:</span>
|
||||
<span className={styles.systemTransfer__detailValue}>
|
||||
{viewingOrder.fromAccountSequence}
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>账户名称:</span>
|
||||
<span className={styles.systemTransfer__detailValue}>
|
||||
{viewingOrder.fromAccountName}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.systemTransfer__detailSection}>
|
||||
<div className={styles.systemTransfer__detailTitle}>目标账户</div>
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>账户序列:</span>
|
||||
<span className={styles.systemTransfer__detailValue}>
|
||||
{viewingOrder.toAccountSequence}
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>用户ID:</span>
|
||||
<span className={styles.systemTransfer__detailValue}>{viewingOrder.toUserId}</span>
|
||||
</div>
|
||||
{viewingOrder.toUserName && (
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>用户姓名:</span>
|
||||
<span className={styles.systemTransfer__detailValue}>
|
||||
{viewingOrder.toUserName}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>钱包地址:</span>
|
||||
<span
|
||||
className={styles.systemTransfer__detailValue}
|
||||
style={{ wordBreak: 'break-all' }}
|
||||
>
|
||||
{viewingOrder.toAddress}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{(viewingOrder.txHash || viewingOrder.errorMessage) && (
|
||||
<div className={styles.systemTransfer__detailSection}>
|
||||
<div className={styles.systemTransfer__detailTitle}>区块链信息</div>
|
||||
{viewingOrder.txHash && (
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>TxHash:</span>
|
||||
<span
|
||||
className={styles.systemTransfer__detailValue}
|
||||
style={{ wordBreak: 'break-all', fontFamily: 'monospace' }}
|
||||
>
|
||||
{viewingOrder.txHash}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{viewingOrder.errorMessage && (
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>错误信息:</span>
|
||||
<span className={styles.systemTransfer__detailValue} style={{ color: '#ff4d4f' }}>
|
||||
{viewingOrder.errorMessage}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{viewingOrder.memo && (
|
||||
<div className={styles.systemTransfer__detailSection}>
|
||||
<div className={styles.systemTransfer__detailTitle}>备注</div>
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailValue}>{viewingOrder.memo}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={styles.systemTransfer__detailSection}>
|
||||
<div className={styles.systemTransfer__detailTitle}>操作信息</div>
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>操作员:</span>
|
||||
<span className={styles.systemTransfer__detailValue}>
|
||||
{viewingOrder.operatorName || viewingOrder.operatorId}
|
||||
</span>
|
||||
</div>
|
||||
{viewingOrder.frozenAt && (
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>冻结时间:</span>
|
||||
<span className={styles.systemTransfer__detailValue}>
|
||||
{formatDateTime(viewingOrder.frozenAt)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{viewingOrder.broadcastedAt && (
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>广播时间:</span>
|
||||
<span className={styles.systemTransfer__detailValue}>
|
||||
{formatDateTime(viewingOrder.broadcastedAt)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{viewingOrder.confirmedAt && (
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>确认时间:</span>
|
||||
<span className={styles.systemTransfer__detailValue}>
|
||||
{formatDateTime(viewingOrder.confirmedAt)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
|
||||
{/* 确认划转弹窗 */}
|
||||
<Modal
|
||||
visible={confirmModalOpen}
|
||||
title="确认划转"
|
||||
onClose={() => setConfirmModalOpen(false)}
|
||||
footer={
|
||||
<div className={styles.systemTransfer__modalFooter}>
|
||||
<Button variant="outline" onClick={() => setConfirmModalOpen(false)}>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={handleSubmitTransfer}
|
||||
loading={requestMutation.isPending}
|
||||
>
|
||||
确认划转
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
width={500}
|
||||
>
|
||||
<div className={styles.systemTransfer__detail}>
|
||||
<div className={styles.systemTransfer__warning}>
|
||||
请仔细核对划转信息,划转一旦提交将无法撤销。
|
||||
</div>
|
||||
<div className={styles.systemTransfer__detailSection}>
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>源账户:</span>
|
||||
<span className={styles.systemTransfer__detailValue}>
|
||||
{selectedAccount?.name} ({selectedAccount?.accountSequence})
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>目标账户:</span>
|
||||
<span className={styles.systemTransfer__detailValue}>
|
||||
{transferForm.toAccountSequence}
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>划转金额:</span>
|
||||
<span className={styles.systemTransfer__detailValue}>
|
||||
{transferForm.amount} USDT
|
||||
</span>
|
||||
</div>
|
||||
{transferForm.memo && (
|
||||
<div className={styles.systemTransfer__detailRow}>
|
||||
<span className={styles.systemTransfer__detailLabel}>备注:</span>
|
||||
<span className={styles.systemTransfer__detailValue}>{transferForm.memo}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</PageContainer>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,427 @@
|
|||
@use '@/styles/variables' as *;
|
||||
|
||||
.systemTransfer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: $text-primary;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-size: 14px;
|
||||
color: $text-secondary;
|
||||
}
|
||||
|
||||
&__card {
|
||||
background: $card-background;
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: $shadow-base;
|
||||
}
|
||||
|
||||
// 标签页
|
||||
&__tabs {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
margin-bottom: 20px;
|
||||
border-bottom: 1px solid $border-color;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
&__tab {
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: $text-secondary;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
margin-bottom: -1px;
|
||||
|
||||
&:hover {
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
&--active {
|
||||
color: $primary-color;
|
||||
border-bottom-color: $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选区域
|
||||
&__filters {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
&__input {
|
||||
padding: 8px 12px;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
min-width: 140px;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__select {
|
||||
padding: 8px 12px;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
min-width: 140px;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
// 列表区域
|
||||
&__list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
&__loading,
|
||||
&__empty,
|
||||
&__error {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 60px 20px;
|
||||
color: $text-secondary;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&__error {
|
||||
color: $error-color;
|
||||
}
|
||||
|
||||
// 表格样式
|
||||
&__table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 14px;
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 12px 16px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid $border-color;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: 600;
|
||||
color: $text-secondary;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
td {
|
||||
color: $text-primary;
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
transition: background 0.15s;
|
||||
|
||||
&:hover {
|
||||
background: #f5f7fa;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__orderNo {
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
color: $text-secondary;
|
||||
}
|
||||
|
||||
&__amount {
|
||||
font-weight: 600;
|
||||
color: $primary-color;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
&__accountTag {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
background: #f0f5ff;
|
||||
color: #2f54eb;
|
||||
|
||||
&--system {
|
||||
background: #fff7e6;
|
||||
color: #fa8c16;
|
||||
}
|
||||
|
||||
&--user {
|
||||
background: #e6f7ff;
|
||||
color: #1677ff;
|
||||
}
|
||||
}
|
||||
|
||||
&__statusTag {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&__accountSequence {
|
||||
font-weight: 600;
|
||||
color: $primary-color;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
&__accountName {
|
||||
font-size: 12px;
|
||||
color: $text-secondary;
|
||||
}
|
||||
|
||||
&__txHash {
|
||||
font-family: monospace;
|
||||
font-size: 11px;
|
||||
color: $text-secondary;
|
||||
max-width: 120px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
// 操作按钮
|
||||
&__actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
&__actionBtn {
|
||||
padding: 4px 10px;
|
||||
font-size: 13px;
|
||||
color: $text-secondary;
|
||||
background: transparent;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: $primary-color;
|
||||
border-color: $primary-color;
|
||||
}
|
||||
|
||||
&--primary {
|
||||
color: $primary-color;
|
||||
border-color: $primary-color;
|
||||
|
||||
&:hover {
|
||||
background: #e6f4ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
&__pagination {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 20px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid $border-color;
|
||||
font-size: 14px;
|
||||
color: $text-secondary;
|
||||
}
|
||||
|
||||
&__pageButtons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
// 新建划转表单
|
||||
&__form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
&__formGroup {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: $text-primary;
|
||||
}
|
||||
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
padding: 10px 12px;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
transition: border-color 0.2s;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: $primary-color;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: $text-disabled;
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
min-height: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
&__formHint {
|
||||
font-size: 12px;
|
||||
color: $text-secondary;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
&__formError {
|
||||
font-size: 12px;
|
||||
color: $error-color;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
&__modalFooter {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
// 详情样式
|
||||
&__detail {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
&__detailSection {
|
||||
padding: 16px;
|
||||
background: #fafafa;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
&__detailTitle {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: $text-primary;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid $border-color;
|
||||
}
|
||||
|
||||
&__detailRow {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 8px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__detailLabel {
|
||||
flex-shrink: 0;
|
||||
width: 80px;
|
||||
font-size: 13px;
|
||||
color: $text-secondary;
|
||||
}
|
||||
|
||||
&__detailValue {
|
||||
flex: 1;
|
||||
font-size: 13px;
|
||||
color: $text-primary;
|
||||
}
|
||||
|
||||
// 账户卡片列表
|
||||
&__accountCards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
&__accountCard {
|
||||
padding: 16px;
|
||||
background: #fafafa;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
border-color: $primary-color;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
&--selected {
|
||||
border-color: $primary-color;
|
||||
background: #e6f4ff;
|
||||
}
|
||||
}
|
||||
|
||||
&__accountCardName {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: $text-primary;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&__accountCardSequence {
|
||||
font-size: 13px;
|
||||
color: $text-secondary;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
&__accountCardBalance {
|
||||
font-size: 14px;
|
||||
color: $primary-color;
|
||||
font-weight: 500;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
// 警告信息
|
||||
&__warning {
|
||||
padding: 12px 16px;
|
||||
background: #fffbe6;
|
||||
border: 1px solid #ffe58f;
|
||||
border-radius: 8px;
|
||||
color: #ad6800;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@ const topMenuItems: MenuItem[] = [
|
|||
{ key: 'notifications', icon: '/images/Container3.svg', label: '通知管理', path: '/notifications' },
|
||||
{ key: 'pending-actions', icon: '/images/Container3.svg', label: '待办操作', path: '/pending-actions' },
|
||||
{ key: 'withdrawals', icon: '/images/Container5.svg', label: '提现审核', path: '/withdrawals' },
|
||||
{ key: 'system-transfer', icon: '/images/Container5.svg', label: '系统划转', path: '/system-transfer' },
|
||||
{ key: 'statistics', icon: '/images/Container5.svg', label: '数据统计', path: '/statistics' },
|
||||
{ key: 'maintenance', icon: '/images/Container6.svg', label: '系统维护', path: '/maintenance' },
|
||||
{ key: 'settings', icon: '/images/Container6.svg', label: '系统设置', path: '/settings' },
|
||||
|
|
|
|||
|
|
@ -3,3 +3,4 @@
|
|||
export * from './useDashboard';
|
||||
export * from './useUsers';
|
||||
export * from './useAuthorizations';
|
||||
export * from './useSystemWithdrawal';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* 系统账户划转管理 Hooks
|
||||
* [2026-01-06] 新增
|
||||
*/
|
||||
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { systemWithdrawalService } from '@/services/systemWithdrawalService';
|
||||
import type {
|
||||
SystemWithdrawalQueryParams,
|
||||
SystemWithdrawalRequest,
|
||||
} from '@/types/system-withdrawal.types';
|
||||
|
||||
/** Query Keys */
|
||||
export const systemWithdrawalKeys = {
|
||||
all: ['systemWithdrawals'] as const,
|
||||
accounts: () => [...systemWithdrawalKeys.all, 'accounts'] as const,
|
||||
orders: (params: SystemWithdrawalQueryParams) => [...systemWithdrawalKeys.all, 'orders', params] as const,
|
||||
accountName: (accountSequence: string) => [...systemWithdrawalKeys.all, 'accountName', accountSequence] as const,
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取可划转的系统账户列表
|
||||
*/
|
||||
export function useSystemWithdrawalAccounts() {
|
||||
return useQuery({
|
||||
queryKey: systemWithdrawalKeys.accounts(),
|
||||
queryFn: () => systemWithdrawalService.getAccounts(),
|
||||
staleTime: 5 * 60 * 1000, // 5分钟
|
||||
gcTime: 10 * 60 * 1000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取划转订单列表
|
||||
*/
|
||||
export function useSystemWithdrawalOrders(params: SystemWithdrawalQueryParams = {}) {
|
||||
return useQuery({
|
||||
queryKey: systemWithdrawalKeys.orders(params),
|
||||
queryFn: () => systemWithdrawalService.getOrders(params),
|
||||
staleTime: 30 * 1000, // 30秒
|
||||
gcTime: 5 * 60 * 1000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取账户名称
|
||||
*/
|
||||
export function useAccountName(accountSequence: string) {
|
||||
return useQuery({
|
||||
queryKey: systemWithdrawalKeys.accountName(accountSequence),
|
||||
queryFn: () => systemWithdrawalService.getAccountName(accountSequence),
|
||||
enabled: !!accountSequence && accountSequence.length > 0,
|
||||
staleTime: 10 * 60 * 1000, // 10分钟
|
||||
gcTime: 30 * 60 * 1000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起划转请求
|
||||
*/
|
||||
export function useRequestSystemWithdrawal() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (data: SystemWithdrawalRequest) => systemWithdrawalService.request(data),
|
||||
onSuccess: () => {
|
||||
// 成功后刷新账户列表和订单列表
|
||||
queryClient.invalidateQueries({ queryKey: systemWithdrawalKeys.all });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -207,6 +207,18 @@ export const API_ENDPOINTS = {
|
|||
COMPLETE_PAYMENT: (orderNo: string) => `/v1/wallets/fiat-withdrawals/${orderNo}/complete-payment`,
|
||||
},
|
||||
|
||||
// [2026-01-06] 新增:系统账户划转 (wallet-service)
|
||||
SYSTEM_WITHDRAWAL: {
|
||||
// 发起划转请求
|
||||
REQUEST: '/v1/wallets/system-withdrawal/request',
|
||||
// 获取可划转账户列表
|
||||
ACCOUNTS: '/v1/wallets/system-withdrawal/accounts',
|
||||
// 查询划转订单
|
||||
ORDERS: '/v1/wallets/system-withdrawal/orders',
|
||||
// 获取账户名称
|
||||
ACCOUNT_NAME: (accountSequence: string) => `/v1/wallets/system-withdrawal/account-name/${accountSequence}`,
|
||||
},
|
||||
|
||||
// [2026-01-04] 新增:系统账户报表 (reporting-service)
|
||||
// 回滚方式:删除此部分即可
|
||||
SYSTEM_ACCOUNT_REPORTS: {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* 系统账户划转服务
|
||||
* [2026-01-06] 新增
|
||||
*/
|
||||
|
||||
import apiClient from '@/infrastructure/api/client';
|
||||
import { API_ENDPOINTS } from '@/infrastructure/api/endpoints';
|
||||
import type {
|
||||
SystemAccount,
|
||||
SystemWithdrawalRequest,
|
||||
SystemWithdrawalResponse,
|
||||
SystemWithdrawalQueryParams,
|
||||
SystemWithdrawalOrderListResponse,
|
||||
} from '@/types/system-withdrawal.types';
|
||||
|
||||
/**
|
||||
* 系统账户划转服务
|
||||
*/
|
||||
export const systemWithdrawalService = {
|
||||
/**
|
||||
* 获取可划转的系统账户列表
|
||||
*/
|
||||
async getAccounts(): Promise<SystemAccount[]> {
|
||||
const response = await apiClient.get(API_ENDPOINTS.SYSTEM_WITHDRAWAL.ACCOUNTS);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const result = (response as any)?.data?.data;
|
||||
return result ?? [];
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取划转订单列表
|
||||
*/
|
||||
async getOrders(params: SystemWithdrawalQueryParams = {}): Promise<SystemWithdrawalOrderListResponse> {
|
||||
const response = await apiClient.get(API_ENDPOINTS.SYSTEM_WITHDRAWAL.ORDERS, { params });
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const result = (response as any)?.data?.data;
|
||||
return result ?? { items: [], total: 0, page: 1, limit: 20 };
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取账户名称
|
||||
*/
|
||||
async getAccountName(accountSequence: string): Promise<{ accountSequence: string; name: string }> {
|
||||
const response = await apiClient.get(API_ENDPOINTS.SYSTEM_WITHDRAWAL.ACCOUNT_NAME(accountSequence));
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const result = (response as any)?.data?.data;
|
||||
return result ?? { accountSequence, name: '未知账户' };
|
||||
},
|
||||
|
||||
/**
|
||||
* 发起划转请求
|
||||
*/
|
||||
async request(data: SystemWithdrawalRequest): Promise<SystemWithdrawalResponse> {
|
||||
const response = await apiClient.post(API_ENDPOINTS.SYSTEM_WITHDRAWAL.REQUEST, data);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return (response as any)?.data?.data;
|
||||
},
|
||||
};
|
||||
|
||||
export default systemWithdrawalService;
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* 系统账户划转类型定义
|
||||
* [2026-01-06] 新增
|
||||
*/
|
||||
|
||||
// 划转订单状态
|
||||
export type SystemWithdrawalStatus = 'PENDING' | 'FROZEN' | 'BROADCASTED' | 'CONFIRMED' | 'FAILED';
|
||||
|
||||
// 系统账户信息
|
||||
export interface SystemAccount {
|
||||
accountSequence: string;
|
||||
name: string;
|
||||
balance?: string;
|
||||
}
|
||||
|
||||
// 划转订单
|
||||
export interface SystemWithdrawalOrder {
|
||||
orderId: number;
|
||||
orderNo: string;
|
||||
fromAccountSequence: string;
|
||||
fromAccountName: string;
|
||||
toAccountSequence: string;
|
||||
toUserId: number;
|
||||
toUserName?: string;
|
||||
toAddress: string;
|
||||
amount: string;
|
||||
chainType: string;
|
||||
txHash?: string;
|
||||
status: SystemWithdrawalStatus;
|
||||
errorMessage?: string;
|
||||
operatorId: string;
|
||||
operatorName?: string;
|
||||
memo?: string;
|
||||
frozenAt?: string;
|
||||
broadcastedAt?: string;
|
||||
confirmedAt?: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
// 划转请求
|
||||
export interface SystemWithdrawalRequest {
|
||||
fromAccountSequence: string;
|
||||
toAccountSequence: string;
|
||||
amount: string;
|
||||
memo?: string;
|
||||
}
|
||||
|
||||
// 划转响应
|
||||
export interface SystemWithdrawalResponse {
|
||||
orderNo: string;
|
||||
status: SystemWithdrawalStatus;
|
||||
message: string;
|
||||
}
|
||||
|
||||
// 订单查询参数
|
||||
export interface SystemWithdrawalQueryParams {
|
||||
fromAccountSequence?: string;
|
||||
toAccountSequence?: string;
|
||||
status?: SystemWithdrawalStatus;
|
||||
page?: number;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
// 订单列表响应
|
||||
export interface SystemWithdrawalOrderListResponse {
|
||||
items: SystemWithdrawalOrder[];
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
}
|
||||
|
||||
// 状态配置
|
||||
export const SYSTEM_WITHDRAWAL_STATUS_CONFIG: Record<SystemWithdrawalStatus, { label: string; color: string }> = {
|
||||
PENDING: { label: '待处理', color: '#faad14' },
|
||||
FROZEN: { label: '已冻结', color: '#1890ff' },
|
||||
BROADCASTED: { label: '已广播', color: '#722ed1' },
|
||||
CONFIRMED: { label: '已确认', color: '#52c41a' },
|
||||
FAILED: { label: '失败', color: '#ff4d4f' },
|
||||
};
|
||||
|
||||
// 获取状态信息
|
||||
export function getSystemWithdrawalStatusInfo(status: SystemWithdrawalStatus) {
|
||||
return SYSTEM_WITHDRAWAL_STATUS_CONFIG[status] || { label: status, color: '#999' };
|
||||
}
|
||||
Loading…
Reference in New Issue