优化:列表分类请求
This commit is contained in:
parent
da9de8c772
commit
38d70e3e56
@ -34,7 +34,7 @@ import {
|
|||||||
} from '@/api/event'
|
} from '@/api/event'
|
||||||
|
|
||||||
// 获取列表
|
// 获取列表
|
||||||
const res = await getPmEventPublic({ page: 1, pageSize: 10, tagSlug: 'crypto' })
|
const res = await getPmEventPublic({ page: 1, pageSize: 10, tagIds: [1, 2] })
|
||||||
const cards = res.data.list.map(mapEventItemToCard)
|
const cards = res.data.list.map(mapEventItemToCard)
|
||||||
|
|
||||||
// 获取详情(需鉴权)
|
// 获取详情(需鉴权)
|
||||||
|
|||||||
358
sdk/approve.ts
Normal file
358
sdk/approve.ts
Normal file
@ -0,0 +1,358 @@
|
|||||||
|
// 跨链USDT授权核心方法 - 修复版(无需外部ethers库)
|
||||||
|
// 适用于支持EIP-1193标准的钱包(如MetaMask)
|
||||||
|
|
||||||
|
interface ChainConfig {
|
||||||
|
chainId: string;
|
||||||
|
name: string;
|
||||||
|
usdtAddress: string;
|
||||||
|
rpcUrl: string;
|
||||||
|
explorer: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 链配置
|
||||||
|
const chains: Record<string, ChainConfig> = {
|
||||||
|
eth: {
|
||||||
|
chainId: '0x1', // Ethereum Mainnet
|
||||||
|
name: 'Ethereum',
|
||||||
|
usdtAddress: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
|
||||||
|
rpcUrl: 'https://mainnet.infura.io/v3/',
|
||||||
|
explorer: 'https://etherscan.io'
|
||||||
|
},
|
||||||
|
bnb: {
|
||||||
|
chainId: '0x38', // Binance Smart Chain Mainnet
|
||||||
|
name: 'Binance Smart Chain',
|
||||||
|
usdtAddress: '0x55d398326f99059fF775485246999027B3197955',
|
||||||
|
rpcUrl: 'https://bsc-dataseed.binance.org/',
|
||||||
|
explorer: 'https://bscscan.com'
|
||||||
|
},
|
||||||
|
polygon: {
|
||||||
|
chainId: '0x89', // Polygon Mainnet
|
||||||
|
name: 'Polygon',
|
||||||
|
usdtAddress: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',
|
||||||
|
rpcUrl: 'https://polygon-rpc.com/',
|
||||||
|
explorer: 'https://polygonscan.com'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// USDT ABI
|
||||||
|
const USDT_ABI = [
|
||||||
|
"function approve(address spender, uint256 value) public returns (bool)",
|
||||||
|
"function allowance(address owner, address spender) view returns (uint256)",
|
||||||
|
"function balanceOf(address owner) view returns (uint256)"
|
||||||
|
];
|
||||||
|
|
||||||
|
// 将数字转换为十六进制字符串
|
||||||
|
function numberToHex(num: number | string): string {
|
||||||
|
return '0x' + BigInt(num).toString(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将十进制数字转换为带指定小数位的整数形式
|
||||||
|
function parseUnits(value: string, decimals: number): string {
|
||||||
|
const [integerPart = '0', decimalPart = ''] = value.split('.');
|
||||||
|
let result = integerPart.replace(/^0+/, '') || '0'; // 移除前导零
|
||||||
|
|
||||||
|
if (decimalPart.length > decimals) {
|
||||||
|
throw new Error(`小数位数超过限制: ${decimals}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const paddedDecimal = decimalPart.padEnd(decimals, '0');
|
||||||
|
result += paddedDecimal;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证钱包连接
|
||||||
|
function validateWallet(): boolean {
|
||||||
|
if (typeof window === 'undefined' || typeof (window as any).ethereum === 'undefined') {
|
||||||
|
throw new Error('请在支持以太坊的钱包浏览器中运行此代码');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前钱包账户
|
||||||
|
async function getAccount(): Promise<string> {
|
||||||
|
try {
|
||||||
|
const accounts = await (window as any).ethereum.request({
|
||||||
|
method: 'eth_requestAccounts'
|
||||||
|
});
|
||||||
|
return accounts[0];
|
||||||
|
} catch (error) {
|
||||||
|
console.error('用户拒绝授权:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前网络ID
|
||||||
|
async function getCurrentNetworkId(): Promise<string> {
|
||||||
|
try {
|
||||||
|
const chainId = await (window as any).ethereum.request({
|
||||||
|
method: 'eth_chainId'
|
||||||
|
});
|
||||||
|
return chainId;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取网络ID失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换网络
|
||||||
|
async function switchNetwork(chainId: string): Promise<void> {
|
||||||
|
const chainName = Object.values(chains).find(c => c.chainId === chainId)?.name || 'Unknown Network';
|
||||||
|
|
||||||
|
try {
|
||||||
|
await (window as any).ethereum.request({
|
||||||
|
method: 'wallet_switchEthereumChain',
|
||||||
|
params: [{ chainId: chainId }],
|
||||||
|
});
|
||||||
|
console.log(`已切换到${chainName}`);
|
||||||
|
} catch (switchError: any) {
|
||||||
|
if (switchError.code === 4902) {
|
||||||
|
// 网络不存在,尝试添加网络
|
||||||
|
const config = Object.values(chains).find(c => c.chainId === chainId);
|
||||||
|
if (!config) {
|
||||||
|
throw new Error(`不支持的网络: ${chainId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await (window as any).ethereum.request({
|
||||||
|
method: 'wallet_addEthereumChain',
|
||||||
|
params: [{
|
||||||
|
chainId: chainId,
|
||||||
|
chainName: config.name,
|
||||||
|
nativeCurrency: {
|
||||||
|
name: chainId === '0x38' ? 'BNB' : chainId === '0x89' ? 'MATIC' : 'ETH',
|
||||||
|
symbol: chainId === '0x38' ? 'BNB' : chainId === '0x89' ? 'MATIC' : 'ETH',
|
||||||
|
decimals: 18,
|
||||||
|
},
|
||||||
|
rpcUrls: [config.rpcUrl],
|
||||||
|
blockExplorerUrls: [config.explorer]
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
console.log(`已添加${chainName}`);
|
||||||
|
} catch (addError) {
|
||||||
|
console.error('添加网络失败:', addError);
|
||||||
|
throw addError;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('切换网络失败:', switchError);
|
||||||
|
throw switchError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编码函数调用数据
|
||||||
|
function encodeFunctionCall(abiFragment: string, args: any[]): string {
|
||||||
|
// 简化的函数签名计算
|
||||||
|
const funcSignature = abiFragment.substring(0, abiFragment.indexOf('('));
|
||||||
|
const params = abiFragment.substring(abiFragment.indexOf('(') + 1, abiFragment.lastIndexOf(')'));
|
||||||
|
|
||||||
|
// 为 approve(address,uint256) 函数构建调用数据
|
||||||
|
if (funcSignature === 'approve' && params === 'address,uint256') {
|
||||||
|
// 函数选择器: keccak256("approve(address,uint256)") 的前4字节
|
||||||
|
// 已知为 0x095ea7b3
|
||||||
|
let data = '0x095ea7b3';
|
||||||
|
|
||||||
|
// 地址参数(补零到32字节)
|
||||||
|
let addr = args[0].toLowerCase();
|
||||||
|
if (addr.startsWith('0x')) addr = addr.substring(2);
|
||||||
|
data += addr.padStart(64, '0');
|
||||||
|
|
||||||
|
// 数量参数(补零到32字节)
|
||||||
|
let amount = BigInt(args[1]).toString(16);
|
||||||
|
data += amount.padStart(64, '0');
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为 allowance(address,address) 函数构建调用数据
|
||||||
|
if (funcSignature === 'allowance' && params === 'address,address') {
|
||||||
|
// 函数选择器: keccak256("allowance(address,address)") 的前4字节
|
||||||
|
// 已知为 0xdd62ed3e
|
||||||
|
let data = '0xdd62ed3e';
|
||||||
|
|
||||||
|
// 第一个地址参数
|
||||||
|
let owner = args[0].toLowerCase();
|
||||||
|
if (owner.startsWith('0x')) owner = owner.substring(2);
|
||||||
|
data += owner.padStart(64, '0');
|
||||||
|
|
||||||
|
// 第二个地址参数
|
||||||
|
let spender = args[1].toLowerCase();
|
||||||
|
if (spender.startsWith('0x')) spender = spender.substring(2);
|
||||||
|
data += spender.padStart(64, '0');
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为 balanceOf(address) 函数构建调用数据
|
||||||
|
if (funcSignature === 'balanceOf' && params === 'address') {
|
||||||
|
// 函数选择器: keccak256("balanceOf(address)") 的前4字节
|
||||||
|
// 已知为 0x70a08231
|
||||||
|
let data = '0x70a08231';
|
||||||
|
|
||||||
|
// 地址参数(补零到32字节)
|
||||||
|
let addr = args[0].toLowerCase();
|
||||||
|
if (addr.startsWith('0x')) addr = addr.substring(2);
|
||||||
|
data += addr.padStart(64, '0');
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('不支持的ABI片段: ' + abiFragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 授权USDT
|
||||||
|
async function authorizeUSDT(
|
||||||
|
chain: 'eth' | 'bnb' | 'polygon',
|
||||||
|
spenderAddress: string,
|
||||||
|
amount: string
|
||||||
|
): Promise<{ success: boolean; transactionHash?: string; error?: any }> {
|
||||||
|
try {
|
||||||
|
// 验证参数
|
||||||
|
if (!isValidAddress(spenderAddress)) {
|
||||||
|
throw new Error('无效的被授权地址');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(parseFloat(amount)) || parseFloat(amount) <= 0) {
|
||||||
|
throw new Error('授权金额必须大于0');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取钱包账户
|
||||||
|
const account = await getAccount();
|
||||||
|
|
||||||
|
// 获取当前网络
|
||||||
|
const currentNetworkId = await getCurrentNetworkId();
|
||||||
|
const targetChainConfig = chains[chain];
|
||||||
|
if (!targetChainConfig) throw new Error(`不支持的链: ${chain}`);
|
||||||
|
|
||||||
|
// 检查是否需要切换网络
|
||||||
|
if (currentNetworkId !== targetChainConfig.chainId) {
|
||||||
|
await switchNetwork(targetChainConfig.chainId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将金额转换为带6位小数的单位(USDT有6位小数)
|
||||||
|
const parsedAmount = parseUnits(amount, 6);
|
||||||
|
|
||||||
|
// 构建交易数据
|
||||||
|
const data = encodeFunctionCall('approve(address,uint256)', [spenderAddress, parsedAmount]);
|
||||||
|
|
||||||
|
// 构建交易对象
|
||||||
|
const tx = {
|
||||||
|
from: account,
|
||||||
|
to: targetChainConfig.usdtAddress,
|
||||||
|
data: data
|
||||||
|
};
|
||||||
|
|
||||||
|
// 发送交易
|
||||||
|
const transactionHash = await (window as any).ethereum.request({
|
||||||
|
method: 'eth_sendTransaction',
|
||||||
|
params: [tx]
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`正在${targetChainConfig.name}上发送授权交易...`);
|
||||||
|
console.log('交易哈希:', transactionHash);
|
||||||
|
|
||||||
|
// 等待交易确认
|
||||||
|
// 注意:这里我们只返回交易哈希,实际等待确认需要轮询或监听
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
transactionHash: transactionHash
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('授权失败:', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询USDT余额
|
||||||
|
async function getUSDTBalance(chain: 'eth' | 'bnb' | 'polygon', account: string): Promise<string> {
|
||||||
|
try {
|
||||||
|
const targetChainConfig = chains[chain];
|
||||||
|
if (!targetChainConfig) throw new Error(`不支持的链: ${chain}`);
|
||||||
|
|
||||||
|
// 构建调用数据
|
||||||
|
const data = encodeFunctionCall('balanceOf(address)', [account]);
|
||||||
|
|
||||||
|
// 执行调用
|
||||||
|
const result = await (window as any).ethereum.request({
|
||||||
|
method: 'eth_call',
|
||||||
|
params: [{
|
||||||
|
to: targetChainConfig.usdtAddress,
|
||||||
|
data: data
|
||||||
|
}, 'latest']
|
||||||
|
});
|
||||||
|
|
||||||
|
// 解析结果(十六进制转十进制)
|
||||||
|
const balance = BigInt(result).toString();
|
||||||
|
|
||||||
|
// 转换为带6位小数的格式
|
||||||
|
if (balance.length <= 6) {
|
||||||
|
return '0.' + balance.padStart(6, '0');
|
||||||
|
} else {
|
||||||
|
const integerPart = balance.slice(0, -6);
|
||||||
|
const decimalPart = balance.slice(-6).replace(/0+$/, ''); // 移除末尾零
|
||||||
|
return decimalPart ? `${integerPart}.${decimalPart}` : integerPart;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('查询余额失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询当前授权额度
|
||||||
|
async function getAllowance(
|
||||||
|
chain: 'eth' | 'bnb' | 'polygon',
|
||||||
|
owner: string,
|
||||||
|
spender: string
|
||||||
|
): Promise<string> {
|
||||||
|
try {
|
||||||
|
const targetChainConfig = chains[chain];
|
||||||
|
if (!targetChainConfig) throw new Error(`不支持的链: ${chain}`);
|
||||||
|
|
||||||
|
// 构建调用数据
|
||||||
|
const data = encodeFunctionCall('allowance(address,address)', [owner, spender]);
|
||||||
|
|
||||||
|
// 执行调用
|
||||||
|
const result = await (window as any).ethereum.request({
|
||||||
|
method: 'eth_call',
|
||||||
|
params: [{
|
||||||
|
to: targetChainConfig.usdtAddress,
|
||||||
|
data: data
|
||||||
|
}, 'latest']
|
||||||
|
});
|
||||||
|
|
||||||
|
// 解析结果(十六进制转十进制)
|
||||||
|
const allowance = BigInt(result).toString();
|
||||||
|
|
||||||
|
// 转换为带6位小数的格式
|
||||||
|
if (allowance.length <= 6) {
|
||||||
|
return '0.' + allowance.padStart(6, '0');
|
||||||
|
} else {
|
||||||
|
const integerPart = allowance.slice(0, -6);
|
||||||
|
const decimalPart = allowance.slice(-6).replace(/0+$/, ''); // 移除末尾零
|
||||||
|
return decimalPart ? `${integerPart}.${decimalPart}` : integerPart;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('查询授权额度失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证地址格式
|
||||||
|
function isValidAddress(address: string): boolean {
|
||||||
|
return /^0x[a-fA-F0-9]{40}$/.test(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出方法供UI调用
|
||||||
|
export const CrossChainUSDTAuth = {
|
||||||
|
authorizeUSDT,
|
||||||
|
getUSDTBalance,
|
||||||
|
getAllowance
|
||||||
|
};
|
||||||
|
|
||||||
|
// 使用示例:
|
||||||
|
// await CrossChainUSDTAuth.authorizeUSDT('eth', '0x1234...', '100')
|
||||||
|
// await CrossChainUSDTAuth.getUSDTBalance('eth', '0x1234...')
|
||||||
|
// await CrossChainUSDTAuth.getAllowance('eth', '0x1234...', '0x5678...')
|
||||||
@ -113,42 +113,39 @@ export interface PmEventListResponse {
|
|||||||
msg: string
|
msg: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /PmEvent/getPmEventPublic 请求参数(与 doc.json 对齐)
|
||||||
|
*/
|
||||||
export interface GetPmEventListParams {
|
export interface GetPmEventListParams {
|
||||||
page?: number
|
page?: number
|
||||||
pageSize?: number
|
pageSize?: number
|
||||||
keyword?: string
|
keyword?: string
|
||||||
/** 创建时间范围,如 ['2025-01-01', '2025-12-31'] */
|
/** 创建时间范围,如 ['2025-01-01', '2025-12-31'],collectionFormat: csv */
|
||||||
createdAtRange?: string[]
|
createdAtRange?: string[]
|
||||||
/** clobTokenIds 对应的值,用于按市场 token 筛选;可从 market.clobTokenIds 获取 */
|
/** 标签 ID 列表,按分类筛选,collectionFormat: csv */
|
||||||
tokenid?: string | string[]
|
tagIds?: number[]
|
||||||
/** 标签 ID,按分类筛选 */
|
|
||||||
tagId?: number
|
|
||||||
/** 标签 slug,按分类筛选 */
|
|
||||||
tagSlug?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页获取 Event 列表(公开接口,不需要鉴权)
|
* 分页获取 Event 列表(公开接口,不需要鉴权)
|
||||||
* GET /PmEvent/getPmEventPublic
|
* GET /PmEvent/getPmEventPublic
|
||||||
*
|
*
|
||||||
* Query: page, pageSize, keyword, createdAtRange, tokenid, tagId, tagSlug
|
* Query: page, pageSize, keyword, createdAtRange, tagIds
|
||||||
|
* doc.json: paths["/PmEvent/getPmEventPublic"].get.parameters
|
||||||
*/
|
*/
|
||||||
export async function getPmEventPublic(
|
export async function getPmEventPublic(
|
||||||
params: GetPmEventListParams = {},
|
params: GetPmEventListParams = {},
|
||||||
): Promise<PmEventListResponse> {
|
): Promise<PmEventListResponse> {
|
||||||
const { page = 1, pageSize = 10, keyword, createdAtRange, tokenid, tagId, tagSlug } = params
|
const { page = 1, pageSize = 10, keyword, createdAtRange, tagIds } = params
|
||||||
const query: Record<string, string | number | string[] | undefined> = {
|
const query: Record<string, string | number | string[] | undefined> = {
|
||||||
page,
|
page,
|
||||||
pageSize,
|
pageSize,
|
||||||
}
|
}
|
||||||
if (keyword != null && keyword !== '') query.keyword = keyword
|
if (keyword != null && keyword !== '') query.keyword = keyword
|
||||||
if (createdAtRange != null && createdAtRange.length) query.createdAtRange = createdAtRange
|
if (createdAtRange != null && createdAtRange.length) query.createdAtRange = createdAtRange
|
||||||
if (tokenid != null) {
|
if (tagIds != null && tagIds.length > 0) {
|
||||||
query.tokenid = Array.isArray(tokenid) ? tokenid : [tokenid]
|
query.tagIds = tagIds.join(',')
|
||||||
}
|
}
|
||||||
// if (tagId != null && Number.isFinite(tagId)) query.tagId = tagId
|
|
||||||
// if (tagSlug != null && tagSlug !== '') query.tagSlug = tagSlug
|
|
||||||
|
|
||||||
return get<PmEventListResponse>('/PmEvent/getPmEventPublic', query)
|
return get<PmEventListResponse>('/PmEvent/getPmEventPublic', query)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
138
src/api/order.ts
Normal file
138
src/api/order.ts
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import { get } from './request'
|
||||||
|
|
||||||
|
/** 分页结果 */
|
||||||
|
export interface PageResult<T> {
|
||||||
|
list: T[]
|
||||||
|
page: number
|
||||||
|
pageSize: number
|
||||||
|
total: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单项(与 doc.json definitions["model.ClobOrder"] 对齐)
|
||||||
|
* GET /clob/order/getOrderList 列表项
|
||||||
|
*/
|
||||||
|
export interface ClobOrderItem {
|
||||||
|
ID: number
|
||||||
|
assetID?: string
|
||||||
|
createdAt?: string
|
||||||
|
updatedAt?: string
|
||||||
|
expiration?: number
|
||||||
|
feeRateBps?: number
|
||||||
|
market?: string
|
||||||
|
orderType?: number
|
||||||
|
originalSize?: number
|
||||||
|
outcome?: string
|
||||||
|
price?: number
|
||||||
|
side?: number
|
||||||
|
sizeMatched?: number
|
||||||
|
status?: number
|
||||||
|
userID?: number
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 订单列表响应 */
|
||||||
|
export interface OrderListResponse {
|
||||||
|
code: number
|
||||||
|
data: PageResult<ClobOrderItem>
|
||||||
|
msg: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /clob/order/getOrderList 请求参数
|
||||||
|
*/
|
||||||
|
export interface GetOrderListParams {
|
||||||
|
page?: number
|
||||||
|
pageSize?: number
|
||||||
|
startCreatedAt?: string
|
||||||
|
endCreatedAt?: string
|
||||||
|
marketID?: string
|
||||||
|
tokenID?: string
|
||||||
|
userID?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页获取订单列表
|
||||||
|
* GET /clob/order/getOrderList
|
||||||
|
* 需鉴权:x-token、x-user-id
|
||||||
|
*/
|
||||||
|
export async function getOrderList(
|
||||||
|
params: GetOrderListParams = {},
|
||||||
|
config?: { headers?: Record<string, string> },
|
||||||
|
): Promise<OrderListResponse> {
|
||||||
|
const { page = 1, pageSize = 10, startCreatedAt, endCreatedAt, marketID, tokenID, userID } = params
|
||||||
|
const query: Record<string, string | number | undefined> = { page, pageSize }
|
||||||
|
if (startCreatedAt != null && startCreatedAt !== '') query.startCreatedAt = startCreatedAt
|
||||||
|
if (endCreatedAt != null && endCreatedAt !== '') query.endCreatedAt = endCreatedAt
|
||||||
|
if (marketID != null && marketID !== '') query.marketID = marketID
|
||||||
|
if (tokenID != null && tokenID !== '') query.tokenID = tokenID
|
||||||
|
if (userID != null && Number.isFinite(userID)) query.userID = userID
|
||||||
|
return get<OrderListResponse>('/clob/order/getOrderList', query, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 钱包 History 展示项(与 Wallet.vue HistoryItem 一致) */
|
||||||
|
export interface HistoryDisplayItem {
|
||||||
|
id: string
|
||||||
|
market: string
|
||||||
|
side: 'Yes' | 'No'
|
||||||
|
activity: string
|
||||||
|
value: string
|
||||||
|
activityDetail?: string
|
||||||
|
profitLoss?: string
|
||||||
|
profitLossNegative?: boolean
|
||||||
|
timeAgo?: string
|
||||||
|
avgPrice?: string
|
||||||
|
shares?: string
|
||||||
|
iconChar?: string
|
||||||
|
iconClass?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Side: Buy=1, Sell=2 */
|
||||||
|
const Side = { Buy: 1, Sell: 2 } as const
|
||||||
|
|
||||||
|
function formatTimeAgo(createdAt: string | undefined): string {
|
||||||
|
if (!createdAt) return ''
|
||||||
|
const d = new Date(createdAt)
|
||||||
|
const now = Date.now()
|
||||||
|
const diff = now - d.getTime()
|
||||||
|
if (diff < 60000) return 'Just now'
|
||||||
|
if (diff < 3600000) return `${Math.floor(diff / 60000)} minutes ago`
|
||||||
|
if (diff < 86400000) return `${Math.floor(diff / 3600000)} hours ago`
|
||||||
|
if (diff < 604800000) return `${Math.floor(diff / 86400000)} days ago`
|
||||||
|
return d.toLocaleDateString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 ClobOrderItem 映射为钱包 History 展示项
|
||||||
|
* price 为整数(已乘 10000),sizeMatched 为已成交份额
|
||||||
|
*/
|
||||||
|
export function mapOrderToHistoryItem(order: ClobOrderItem): HistoryDisplayItem {
|
||||||
|
const id = String(order.ID ?? '')
|
||||||
|
const market = order.market ?? ''
|
||||||
|
const outcome = order.outcome ?? 'Yes'
|
||||||
|
const sideNum = order.side ?? Side.Buy
|
||||||
|
const sideLabel = sideNum === Side.Sell ? 'Sell' : 'Buy'
|
||||||
|
const activity = `${sideLabel} ${outcome}`
|
||||||
|
const priceBps = order.price ?? 0
|
||||||
|
const priceCents = Math.round(priceBps / 100)
|
||||||
|
const size = order.sizeMatched ?? order.originalSize ?? 0
|
||||||
|
const valueUsd = (priceBps / 10000) * size
|
||||||
|
const value = `$${valueUsd.toFixed(2)}`
|
||||||
|
const verb = sideNum === Side.Sell ? 'Sold' : 'Bought'
|
||||||
|
const activityDetail = `${verb} ${size} ${outcome} at ${priceCents}¢`
|
||||||
|
const avgPrice = `${priceCents}¢`
|
||||||
|
const timeAgo = formatTimeAgo(order.createdAt)
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
market,
|
||||||
|
side: outcome === 'No' ? 'No' : 'Yes',
|
||||||
|
activity,
|
||||||
|
value,
|
||||||
|
activityDetail,
|
||||||
|
profitLoss: value,
|
||||||
|
profitLossNegative: false,
|
||||||
|
timeAgo,
|
||||||
|
avgPrice,
|
||||||
|
shares: String(size),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -108,6 +108,8 @@
|
|||||||
"today": "Today",
|
"today": "Today",
|
||||||
"deposit": "Deposit",
|
"deposit": "Deposit",
|
||||||
"withdraw": "Withdraw",
|
"withdraw": "Withdraw",
|
||||||
|
"authorize": "Authorize",
|
||||||
|
"authorizeDesc": "Authorize USDC spending for trading. This allows the exchange contract to use your balance when placing orders.",
|
||||||
"profitLoss": "Profit/Loss",
|
"profitLoss": "Profit/Loss",
|
||||||
"allTime": "All-Time",
|
"allTime": "All-Time",
|
||||||
"pl1D": "1D",
|
"pl1D": "1D",
|
||||||
@ -187,4 +189,4 @@
|
|||||||
"ja": "日本語",
|
"ja": "日本語",
|
||||||
"ko": "한국어"
|
"ko": "한국어"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,6 +108,8 @@
|
|||||||
"today": "今日",
|
"today": "今日",
|
||||||
"deposit": "入金",
|
"deposit": "入金",
|
||||||
"withdraw": "出金",
|
"withdraw": "出金",
|
||||||
|
"authorize": "承認",
|
||||||
|
"authorizeDesc": "取引のため USDC の使用を承認します。注文時に取引所が残高を使用できるようになります。",
|
||||||
"profitLoss": "損益",
|
"profitLoss": "損益",
|
||||||
"allTime": "全期間",
|
"allTime": "全期間",
|
||||||
"pl1D": "1日",
|
"pl1D": "1日",
|
||||||
@ -187,4 +189,4 @@
|
|||||||
"ja": "日本語",
|
"ja": "日本語",
|
||||||
"ko": "한국어"
|
"ko": "한국어"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,6 +108,8 @@
|
|||||||
"today": "오늘",
|
"today": "오늘",
|
||||||
"deposit": "입금",
|
"deposit": "입금",
|
||||||
"withdraw": "출금",
|
"withdraw": "출금",
|
||||||
|
"authorize": "승인",
|
||||||
|
"authorizeDesc": "거래를 위해 USDC 사용을 승인합니다. 주문 시 거래소가 잔액을 사용할 수 있습니다.",
|
||||||
"profitLoss": "손익",
|
"profitLoss": "손익",
|
||||||
"allTime": "전체",
|
"allTime": "전체",
|
||||||
"pl1D": "1일",
|
"pl1D": "1일",
|
||||||
@ -187,4 +189,4 @@
|
|||||||
"ja": "日本語",
|
"ja": "日本語",
|
||||||
"ko": "한국어"
|
"ko": "한국어"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,6 +108,8 @@
|
|||||||
"today": "今日",
|
"today": "今日",
|
||||||
"deposit": "入金",
|
"deposit": "入金",
|
||||||
"withdraw": "提现",
|
"withdraw": "提现",
|
||||||
|
"authorize": "授权",
|
||||||
|
"authorizeDesc": "授权 USDC 用于交易。允许交易合约在下单时使用您的余额。",
|
||||||
"profitLoss": "盈亏",
|
"profitLoss": "盈亏",
|
||||||
"allTime": "全部",
|
"allTime": "全部",
|
||||||
"pl1D": "1天",
|
"pl1D": "1天",
|
||||||
|
|||||||
@ -108,6 +108,8 @@
|
|||||||
"today": "今日",
|
"today": "今日",
|
||||||
"deposit": "入金",
|
"deposit": "入金",
|
||||||
"withdraw": "提現",
|
"withdraw": "提現",
|
||||||
|
"authorize": "授權",
|
||||||
|
"authorizeDesc": "授權 USDC 用於交易。允許交易合約在下單時使用您的餘額。",
|
||||||
"profitLoss": "盈虧",
|
"profitLoss": "盈虧",
|
||||||
"allTime": "全部",
|
"allTime": "全部",
|
||||||
"pl1D": "1天",
|
"pl1D": "1天",
|
||||||
|
|||||||
@ -44,9 +44,14 @@ export const useToastStore = defineStore('toast', () => {
|
|||||||
if (now - last >= DEDUP_MS) return false
|
if (now - last >= DEDUP_MS) return false
|
||||||
|
|
||||||
const msg = normalizeMsg(item.message)
|
const msg = normalizeMsg(item.message)
|
||||||
const inDisplayingIdx = displaying.value.findLastIndex(
|
let inDisplayingIdx = -1
|
||||||
(d) => normalizeMsg(d.message) === msg && d.type === item.type
|
for (let i = displaying.value.length - 1; i >= 0; i--) {
|
||||||
)
|
const d = displaying.value[i]
|
||||||
|
if (d && normalizeMsg(d.message) === msg && d.type === item.type) {
|
||||||
|
inDisplayingIdx = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
if (inDisplayingIdx >= 0) {
|
if (inDisplayingIdx >= 0) {
|
||||||
displaying.value = displaying.value.map((x, i) =>
|
displaying.value = displaying.value.map((x, i) =>
|
||||||
i === inDisplayingIdx
|
i === inDisplayingIdx
|
||||||
@ -95,7 +100,7 @@ export const useToastStore = defineStore('toast', () => {
|
|||||||
function remove(id: string) {
|
function remove(id: string) {
|
||||||
displaying.value = displaying.value.filter((d) => d.id !== id)
|
displaying.value = displaying.value.filter((d) => d.id !== id)
|
||||||
if (queue.value.length > 0) {
|
if (queue.value.length > 0) {
|
||||||
const next = queue.value[0]
|
const next = queue.value[0]!
|
||||||
queue.value = queue.value.slice(1)
|
queue.value = queue.value.slice(1)
|
||||||
displaying.value = [...displaying.value, next]
|
displaying.value = [...displaying.value, next]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -415,16 +415,14 @@ function findNodeById(nodes: CategoryTreeNode[], id: string): CategoryTreeNode |
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 当前选中分类的 tag 筛选(取最后选中的层级,用于 API tagId/tagSlug) */
|
/** 当前选中分类的 tagIds:[第一层, 第二层, 第三层],仅包含数字 ID */
|
||||||
const activeTagFilter = computed(() => {
|
const activeTagIds = computed(() => {
|
||||||
const ids = layerActiveValues.value
|
const ids = layerActiveValues.value
|
||||||
if (ids.length === 0) return { tagId: undefined as number | undefined, tagSlug: undefined as string | undefined }
|
const tagIds: number[] = []
|
||||||
const lastId = ids[ids.length - 1]
|
for (const id of ids) {
|
||||||
const root = filterVisible(categoryTree.value)
|
if (id && /^\d+$/.test(id)) tagIds.push(parseInt(id, 10))
|
||||||
const node = lastId ? findNodeById(root, lastId) : undefined
|
}
|
||||||
if (!node) return { tagId: undefined, tagSlug: undefined }
|
return tagIds
|
||||||
const tagId = /^\d+$/.test(node.id) ? parseInt(node.id, 10) : undefined
|
|
||||||
return { tagId, tagSlug: node.slug || undefined }
|
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 当前展示的层级数据:[[layer0], [layer1]?, [layer2]?] */
|
/** 当前展示的层级数据:[[layer0], [layer1]?, [layer2]?] */
|
||||||
@ -596,14 +594,13 @@ const activeSearchKeyword = ref('')
|
|||||||
/** 请求事件列表并追加或覆盖到 eventList(公开接口,无需鉴权);成功后会更新内存缓存 */
|
/** 请求事件列表并追加或覆盖到 eventList(公开接口,无需鉴权);成功后会更新内存缓存 */
|
||||||
async function loadEvents(page: number, append: boolean, keyword?: string) {
|
async function loadEvents(page: number, append: boolean, keyword?: string) {
|
||||||
const kw = keyword !== undefined ? keyword : activeSearchKeyword.value
|
const kw = keyword !== undefined ? keyword : activeSearchKeyword.value
|
||||||
const { tagId, tagSlug } = activeTagFilter.value
|
const tagIds = activeTagIds.value
|
||||||
try {
|
try {
|
||||||
const res = await getPmEventPublic({
|
const res = await getPmEventPublic({
|
||||||
page,
|
page,
|
||||||
pageSize: PAGE_SIZE,
|
pageSize: PAGE_SIZE,
|
||||||
keyword: kw || undefined,
|
keyword: kw || undefined,
|
||||||
tagId,
|
tagIds: tagIds.length > 0 ? tagIds : undefined,
|
||||||
tagSlug,
|
|
||||||
})
|
})
|
||||||
if (res.code !== 0 && res.code !== 200) {
|
if (res.code !== 0 && res.code !== 200) {
|
||||||
throw new Error(res.msg || '请求失败')
|
throw new Error(res.msg || '请求失败')
|
||||||
@ -656,7 +653,7 @@ function checkScrollLoad() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
/** 分类树就绪后加载列表(确保 activeTagFilter 已计算,与下拉刷新参数一致) */
|
/** 分类树就绪后加载列表(确保 activeTagIds 已计算,与下拉刷新参数一致) */
|
||||||
function loadEventListAfterCategoryReady() {
|
function loadEventListAfterCategoryReady() {
|
||||||
const cached = getEventListCache()
|
const cached = getEventListCache()
|
||||||
if (cached && cached.list.length > 0) {
|
if (cached && cached.list.length > 0) {
|
||||||
|
|||||||
@ -35,6 +35,15 @@
|
|||||||
>
|
>
|
||||||
{{ t('wallet.withdraw') }}
|
{{ t('wallet.withdraw') }}
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
<!-- <v-btn
|
||||||
|
variant="outlined"
|
||||||
|
color="grey"
|
||||||
|
class="action-btn"
|
||||||
|
prepend-icon="mdi-shield-check-outline"
|
||||||
|
@click="onAuthorizeClick"
|
||||||
|
>
|
||||||
|
{{ t('wallet.authorize') }}
|
||||||
|
</v-btn> -->
|
||||||
</div>
|
</div>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
@ -396,7 +405,10 @@
|
|||||||
<template v-else-if="activeTab === 'history'">
|
<template v-else-if="activeTab === 'history'">
|
||||||
<!-- 移动端:历史卡片列表 -->
|
<!-- 移动端:历史卡片列表 -->
|
||||||
<div v-if="mobile" class="history-mobile-list">
|
<div v-if="mobile" class="history-mobile-list">
|
||||||
<template v-if="filteredHistory.length === 0">
|
<template v-if="historyLoading">
|
||||||
|
<div class="empty-cell">{{ t('common.loading') }}</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="filteredHistory.length === 0">
|
||||||
<div class="empty-cell">{{ t('wallet.noHistoryFound') }}</div>
|
<div class="empty-cell">{{ t('wallet.noHistoryFound') }}</div>
|
||||||
</template>
|
</template>
|
||||||
<div
|
<div
|
||||||
@ -462,7 +474,10 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-if="filteredHistory.length === 0">
|
<tr v-if="historyLoading">
|
||||||
|
<td colspan="3" class="empty-cell">{{ t('common.loading') }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-else-if="filteredHistory.length === 0">
|
||||||
<td colspan="3" class="empty-cell">{{ t('wallet.noHistoryFound') }}</td>
|
<td colspan="3" class="empty-cell">{{ t('wallet.noHistoryFound') }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="h in paginatedHistory" :key="h.id">
|
<tr v-for="h in paginatedHistory" :key="h.id">
|
||||||
@ -510,6 +525,33 @@
|
|||||||
@success="onWithdrawSuccess"
|
@success="onWithdrawSuccess"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- 授权弹窗 -->
|
||||||
|
<v-dialog
|
||||||
|
v-model="authorizeDialogOpen"
|
||||||
|
max-width="420"
|
||||||
|
persistent
|
||||||
|
transition="dialog-transition"
|
||||||
|
>
|
||||||
|
<v-card rounded="lg">
|
||||||
|
<v-card-title class="d-flex align-center">
|
||||||
|
<v-icon class="mr-2">mdi-shield-check-outline</v-icon>
|
||||||
|
{{ t('wallet.authorize') }}
|
||||||
|
</v-card-title>
|
||||||
|
<v-card-text>
|
||||||
|
{{ t('wallet.authorizeDesc') }}
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer />
|
||||||
|
<v-btn variant="text" @click="authorizeDialogOpen = false">
|
||||||
|
{{ t('deposit.close') }}
|
||||||
|
</v-btn>
|
||||||
|
<v-btn color="primary" variant="flat" @click="submitAuthorize">
|
||||||
|
{{ t('wallet.authorize') }}
|
||||||
|
</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
|
||||||
<!-- Sell position dialog -->
|
<!-- Sell position dialog -->
|
||||||
<v-dialog
|
<v-dialog
|
||||||
v-model="sellDialogOpen"
|
v-model="sellDialogOpen"
|
||||||
@ -573,6 +615,7 @@ import DepositDialog from '../components/DepositDialog.vue'
|
|||||||
import WithdrawDialog from '../components/WithdrawDialog.vue'
|
import WithdrawDialog from '../components/WithdrawDialog.vue'
|
||||||
import { useUserStore } from '../stores/user'
|
import { useUserStore } from '../stores/user'
|
||||||
import { pmCancelOrder } from '../api/market'
|
import { pmCancelOrder } from '../api/market'
|
||||||
|
import { getOrderList, mapOrderToHistoryItem } from '../api/order'
|
||||||
import {
|
import {
|
||||||
MOCK_TOKEN_ID,
|
MOCK_TOKEN_ID,
|
||||||
MOCK_WALLET_POSITIONS,
|
MOCK_WALLET_POSITIONS,
|
||||||
@ -580,6 +623,7 @@ import {
|
|||||||
MOCK_WALLET_HISTORY,
|
MOCK_WALLET_HISTORY,
|
||||||
} from '../api/mockData'
|
} from '../api/mockData'
|
||||||
import { USE_MOCK_WALLET } from '../config/mock'
|
import { USE_MOCK_WALLET } from '../config/mock'
|
||||||
|
import { CrossChainUSDTAuth } from '../../sdk/approve'
|
||||||
|
|
||||||
const { mobile } = useDisplay()
|
const { mobile } = useDisplay()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
@ -596,6 +640,7 @@ const activeTab = ref<'positions' | 'orders' | 'history'>('positions')
|
|||||||
const search = ref('')
|
const search = ref('')
|
||||||
const depositDialogOpen = ref(false)
|
const depositDialogOpen = ref(false)
|
||||||
const withdrawDialogOpen = ref(false)
|
const withdrawDialogOpen = ref(false)
|
||||||
|
const authorizeDialogOpen = ref(false)
|
||||||
const sellDialogOpen = ref(false)
|
const sellDialogOpen = ref(false)
|
||||||
const sellPositionItem = ref<Position | null>(null)
|
const sellPositionItem = ref<Position | null>(null)
|
||||||
/** 移动端展开的持仓 id,null 表示全部折叠 */
|
/** 移动端展开的持仓 id,null 表示全部折叠 */
|
||||||
@ -685,6 +730,51 @@ const openOrders = ref<OpenOrder[]>(
|
|||||||
const history = ref<HistoryItem[]>(
|
const history = ref<HistoryItem[]>(
|
||||||
USE_MOCK_WALLET ? [...MOCK_WALLET_HISTORY] : [],
|
USE_MOCK_WALLET ? [...MOCK_WALLET_HISTORY] : [],
|
||||||
)
|
)
|
||||||
|
/** 订单历史(API 数据,非 mock 时使用) */
|
||||||
|
const historyList = ref<HistoryItem[]>([])
|
||||||
|
const historyTotal = ref(0)
|
||||||
|
const historyLoading = ref(false)
|
||||||
|
|
||||||
|
async function loadHistoryOrders() {
|
||||||
|
if (USE_MOCK_WALLET) return
|
||||||
|
const headers = userStore.getAuthHeaders()
|
||||||
|
if (!headers) {
|
||||||
|
historyList.value = []
|
||||||
|
historyTotal.value = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const uid = userStore.user?.id ?? userStore.user?.ID
|
||||||
|
const userID = uid != null ? Number(uid) : undefined
|
||||||
|
if (!userID || !Number.isFinite(userID)) {
|
||||||
|
historyList.value = []
|
||||||
|
historyTotal.value = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
historyLoading.value = true
|
||||||
|
try {
|
||||||
|
const res = await getOrderList(
|
||||||
|
{
|
||||||
|
page: page.value,
|
||||||
|
pageSize: itemsPerPage.value,
|
||||||
|
userID,
|
||||||
|
},
|
||||||
|
{ headers },
|
||||||
|
)
|
||||||
|
if (res.code === 0 || res.code === 200) {
|
||||||
|
const list = res.data?.list ?? []
|
||||||
|
historyList.value = list.map(mapOrderToHistoryItem)
|
||||||
|
historyTotal.value = res.data?.total ?? 0
|
||||||
|
} else {
|
||||||
|
historyList.value = []
|
||||||
|
historyTotal.value = 0
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
historyList.value = []
|
||||||
|
historyTotal.value = 0
|
||||||
|
} finally {
|
||||||
|
historyLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function matchSearch(text: string): boolean {
|
function matchSearch(text: string): boolean {
|
||||||
const q = search.value.trim().toLowerCase()
|
const q = search.value.trim().toLowerCase()
|
||||||
@ -692,7 +782,10 @@ function matchSearch(text: string): boolean {
|
|||||||
}
|
}
|
||||||
const filteredPositions = computed(() => positions.value.filter((p) => matchSearch(p.market)))
|
const filteredPositions = computed(() => positions.value.filter((p) => matchSearch(p.market)))
|
||||||
const filteredOpenOrders = computed(() => openOrders.value.filter((o) => matchSearch(o.market)))
|
const filteredOpenOrders = computed(() => openOrders.value.filter((o) => matchSearch(o.market)))
|
||||||
const filteredHistory = computed(() => history.value.filter((h) => matchSearch(h.market)))
|
const filteredHistory = computed(() => {
|
||||||
|
const list = USE_MOCK_WALLET ? history.value : historyList.value
|
||||||
|
return list.filter((h) => matchSearch(h.market))
|
||||||
|
})
|
||||||
|
|
||||||
const page = ref(1)
|
const page = ref(1)
|
||||||
const itemsPerPage = ref(10)
|
const itemsPerPage = ref(10)
|
||||||
@ -704,7 +797,10 @@ function paginate<T>(list: T[]) {
|
|||||||
}
|
}
|
||||||
const paginatedPositions = computed(() => paginate(filteredPositions.value))
|
const paginatedPositions = computed(() => paginate(filteredPositions.value))
|
||||||
const paginatedOpenOrders = computed(() => paginate(filteredOpenOrders.value))
|
const paginatedOpenOrders = computed(() => paginate(filteredOpenOrders.value))
|
||||||
const paginatedHistory = computed(() => paginate(filteredHistory.value))
|
const paginatedHistory = computed(() => {
|
||||||
|
if (USE_MOCK_WALLET) return paginate(filteredHistory.value)
|
||||||
|
return filteredHistory.value
|
||||||
|
})
|
||||||
|
|
||||||
const totalPagesPositions = computed(() =>
|
const totalPagesPositions = computed(() =>
|
||||||
Math.max(1, Math.ceil(filteredPositions.value.length / itemsPerPage.value)),
|
Math.max(1, Math.ceil(filteredPositions.value.length / itemsPerPage.value)),
|
||||||
@ -712,14 +808,15 @@ const totalPagesPositions = computed(() =>
|
|||||||
const totalPagesOrders = computed(() =>
|
const totalPagesOrders = computed(() =>
|
||||||
Math.max(1, Math.ceil(filteredOpenOrders.value.length / itemsPerPage.value)),
|
Math.max(1, Math.ceil(filteredOpenOrders.value.length / itemsPerPage.value)),
|
||||||
)
|
)
|
||||||
const totalPagesHistory = computed(() =>
|
const totalPagesHistory = computed(() => {
|
||||||
Math.max(1, Math.ceil(filteredHistory.value.length / itemsPerPage.value)),
|
const total = USE_MOCK_WALLET ? filteredHistory.value.length : historyTotal.value
|
||||||
)
|
return Math.max(1, Math.ceil(total / itemsPerPage.value))
|
||||||
|
})
|
||||||
|
|
||||||
const currentListTotal = computed(() => {
|
const currentListTotal = computed(() => {
|
||||||
if (activeTab.value === 'positions') return filteredPositions.value.length
|
if (activeTab.value === 'positions') return filteredPositions.value.length
|
||||||
if (activeTab.value === 'orders') return filteredOpenOrders.value.length
|
if (activeTab.value === 'orders') return filteredOpenOrders.value.length
|
||||||
return filteredHistory.value.length
|
return USE_MOCK_WALLET ? filteredHistory.value.length : historyTotal.value
|
||||||
})
|
})
|
||||||
const currentTotalPages = computed(() => {
|
const currentTotalPages = computed(() => {
|
||||||
if (activeTab.value === 'positions') return totalPagesPositions.value
|
if (activeTab.value === 'positions') return totalPagesPositions.value
|
||||||
@ -733,8 +830,12 @@ const currentPageEnd = computed(() =>
|
|||||||
Math.min(page.value * itemsPerPage.value, currentListTotal.value),
|
Math.min(page.value * itemsPerPage.value, currentListTotal.value),
|
||||||
)
|
)
|
||||||
|
|
||||||
watch(activeTab, () => {
|
watch(activeTab, (tab) => {
|
||||||
page.value = 1
|
page.value = 1
|
||||||
|
if (tab === 'history' && !USE_MOCK_WALLET) loadHistoryOrders()
|
||||||
|
})
|
||||||
|
watch([page, itemsPerPage], () => {
|
||||||
|
if (activeTab.value === 'history' && !USE_MOCK_WALLET) loadHistoryOrders()
|
||||||
})
|
})
|
||||||
watch([currentListTotal, itemsPerPage], () => {
|
watch([currentListTotal, itemsPerPage], () => {
|
||||||
const maxPage = currentTotalPages.value
|
const maxPage = currentTotalPages.value
|
||||||
@ -966,6 +1067,16 @@ onUnmounted(() => {
|
|||||||
function onWithdrawSuccess() {
|
function onWithdrawSuccess() {
|
||||||
withdrawDialogOpen.value = false
|
withdrawDialogOpen.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onAuthorizeClick() {
|
||||||
|
authorizeDialogOpen.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
async function submitAuthorize() {
|
||||||
|
// TODO: 对接 USDC 授权接口(approve CLOB 合约)
|
||||||
|
// authorizeDialogOpen.value = false
|
||||||
|
await CrossChainUSDTAuth.authorizeUSDT('eth', '0x024b7270Ee9c0Fc0de2E00a979d146255E0e9C00', '100')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user