feat: 优化订单列表筛选功能,支持按市场标题搜索并改进分组体验

- 后端:MarketGroupedOrdersRequest 添加 marketId 和 marketTitle 字段
- 后端:买入/卖出订单分组接口支持市场 ID 模糊匹配和市场标题关键字筛选
- 前端:BuyOrdersTab 添加市场标题筛选,移除方向筛选,记录用户分组偏好
- 前端:SellOrdersTab 添加市场标题筛选,将方向筛选改为状态筛选,移除方向列
- 前端:MatchedOrdersTab 添加市场标题筛选和市场列显示
- 前端:所有搜索输入框添加 0.5 秒防抖优化
- 前端:分组偏好保存到 localStorage 以便跨会话持久化
This commit is contained in:
WrBug
2026-01-12 10:01:20 +08:00
parent 90fa487d1b
commit 279806da2b
7 changed files with 220 additions and 100 deletions
@@ -110,7 +110,7 @@ data class OrderTrackingRequest(
val page: Int? = 1,
val limit: Int? = 20,
val marketId: String? = null,
val side: String? = null,
val marketTitle: String? = null, // 市场标题关键字筛选
val status: String? = null,
val sellOrderId: String? = null,
val buyOrderId: String? = null
@@ -123,7 +123,9 @@ data class MarketGroupedOrdersRequest(
val copyTradingId: Long,
val type: String, // buy, sell, matched
val page: Int? = 1,
val limit: Int? = 20
val limit: Int? = 20,
val marketId: String? = null,
val marketTitle: String? = null
)
/**
@@ -134,12 +134,21 @@ class CopyTradingStatisticsService(
private fun getBuyOrderList(request: OrderTrackingRequest): Pair<List<BuyOrderInfo>, Long> {
var orders = copyOrderTrackingRepository.findByCopyTradingId(request.copyTradingId)
// 批量获取市场信息(用于筛选)
val allMarketIds = orders.map { it.marketId }.distinct()
val markets = marketService.getMarkets(allMarketIds)
// 筛选
if (!request.marketId.isNullOrBlank()) {
orders = orders.filter { it.marketId == request.marketId }
// marketId 支持模糊匹配
orders = orders.filter { it.marketId.contains(request.marketId!!, ignoreCase = true) }
}
if (!request.side.isNullOrBlank()) {
orders = orders.filter { it.side == request.side }
if (!request.marketTitle.isNullOrBlank()) {
// marketTitle 关键字筛选
orders = orders.filter { order ->
val market = markets[order.marketId]
market?.title?.contains(request.marketTitle!!, ignoreCase = true) == true
}
}
if (!request.status.isNullOrBlank()) {
orders = orders.filter { it.status == request.status }
@@ -157,10 +166,6 @@ class CopyTradingStatisticsService(
val end = minOf(start + limit, orders.size)
val pagedOrders = if (start < orders.size) orders.subList(start, end) else emptyList()
// 批量获取市场信息
val marketIds = pagedOrders.map { it.marketId }.distinct()
val markets = marketService.getMarkets(marketIds)
// 转换为DTO
val list = pagedOrders.map { order ->
val amount = order.quantity.toSafeBigDecimal().multi(order.price)
@@ -193,12 +198,21 @@ class CopyTradingStatisticsService(
private fun getSellOrderList(request: OrderTrackingRequest): Pair<List<SellOrderInfo>, Long> {
var records = sellMatchRecordRepository.findByCopyTradingId(request.copyTradingId)
// 批量获取市场信息(用于筛选)
val allMarketIds = records.map { it.marketId }.distinct()
val markets = marketService.getMarkets(allMarketIds)
// 筛选
if (!request.marketId.isNullOrBlank()) {
records = records.filter { it.marketId == request.marketId }
// marketId 支持模糊匹配
records = records.filter { it.marketId.contains(request.marketId!!, ignoreCase = true) }
}
if (!request.side.isNullOrBlank()) {
records = records.filter { it.side == request.side }
if (!request.marketTitle.isNullOrBlank()) {
// marketTitle 关键字筛选
records = records.filter { record ->
val market = markets[record.marketId]
market?.title?.contains(request.marketTitle!!, ignoreCase = true) == true
}
}
val total = records.size.toLong()
@@ -213,10 +227,6 @@ class CopyTradingStatisticsService(
val end = minOf(start + limit, records.size)
val pagedRecords = if (start < records.size) records.subList(start, end) else emptyList()
// 批量获取市场信息
val marketIds = pagedRecords.map { it.marketId }.distinct()
val markets = marketService.getMarkets(marketIds)
// 转换为DTO
val list = pagedRecords.map { record ->
val amount = record.totalMatchedQuantity.toSafeBigDecimal().multi(record.sellPrice)
@@ -247,6 +257,14 @@ class CopyTradingStatisticsService(
private fun getMatchedOrderList(request: OrderTrackingRequest): Pair<List<MatchedOrderInfo>, Long> {
val matchDetails = sellMatchDetailRepository.findByCopyTradingId(request.copyTradingId)
// 获取所有相关的卖出记录(用于筛选)
val matchRecordIds = matchDetails.map { it.matchRecordId }.distinct()
val matchRecords = matchRecordIds.mapNotNull { id ->
sellMatchRecordRepository.findById(id).orElse(null)
}
val marketIds = matchRecords.map { it.marketId }.distinct()
val markets = marketService.getMarkets(marketIds)
// 筛选
var filtered = matchDetails
if (!request.sellOrderId.isNullOrBlank()) {
@@ -260,6 +278,21 @@ class CopyTradingStatisticsService(
if (!request.buyOrderId.isNullOrBlank()) {
filtered = filtered.filter { it.buyOrderId == request.buyOrderId }
}
if (!request.marketId.isNullOrBlank()) {
// marketId 支持模糊匹配
filtered = filtered.filter { detail ->
val matchRecord = matchRecords.find { it.id == detail.matchRecordId }
matchRecord?.marketId?.contains(request.marketId!!, ignoreCase = true) == true
}
}
if (!request.marketTitle.isNullOrBlank()) {
// marketTitle 关键字筛选
filtered = filtered.filter { detail ->
val matchRecord = matchRecords.find { it.id == detail.matchRecordId }
val market = matchRecord?.let { markets[it.marketId] }
market?.title?.contains(request.marketTitle!!, ignoreCase = true) == true
}
}
val total = filtered.size.toLong()
@@ -274,17 +307,17 @@ class CopyTradingStatisticsService(
val pagedDetails = if (start < filtered.size) filtered.subList(start, end) else emptyList()
// 获取匹配记录以获取市场ID
val matchRecordIds = pagedDetails.map { it.matchRecordId }.distinct()
val matchRecords = matchRecordIds.mapNotNull { id ->
val pagedMatchRecordIds = pagedDetails.map { it.matchRecordId }.distinct()
val pagedMatchRecords = pagedMatchRecordIds.mapNotNull { id ->
sellMatchRecordRepository.findById(id).orElse(null)
}
val marketIds = matchRecords.map { it.marketId }.distinct()
val markets = marketService.getMarkets(marketIds)
val pagedMarketIds = pagedMatchRecords.map { it.marketId }.distinct()
val pagedMarkets = marketService.getMarkets(pagedMarketIds)
// 转换为DTO
val list = pagedDetails.map { detail ->
val matchRecord = matchRecords.find { it.id == detail.matchRecordId }
val market = matchRecord?.let { markets[it.marketId] }
val matchRecord = pagedMatchRecords.find { it.id == detail.matchRecordId }
val market = matchRecord?.let { pagedMarkets[it.marketId] }
MatchedOrderInfo(
sellOrderId = matchRecord?.sellOrderId ?: "",
buyOrderId = detail.buyOrderId,
@@ -550,7 +583,23 @@ class CopyTradingStatisticsService(
// 2. 获取所有买入订单
var orders = copyOrderTrackingRepository.findByCopyTradingId(request.copyTradingId)
// 3. 按市场ID分组
// 3. 批量获取市场信息(用于筛选)
val allMarketIds = orders.map { it.marketId }.distinct()
val markets = marketService.getMarkets(allMarketIds)
// 4. 筛选
if (!request.marketId.isNullOrBlank()) {
// marketId 支持模糊匹配
orders = orders.filter { it.marketId.contains(request.marketId!!, ignoreCase = true) }
}
if (!request.marketTitle.isNullOrBlank()) {
// marketTitle 关键字筛选
orders = orders.filter { order ->
val market = markets[order.marketId]
market?.title?.contains(request.marketTitle!!, ignoreCase = true) == true
}
}
// 5. 按市场ID分组
val groups = mutableMapOf<String, MutableList<CopyOrderTracking>>()
orders.forEach { order ->
val marketId = order.marketId
@@ -562,7 +611,6 @@ class CopyTradingStatisticsService(
// 4. 转换为分组数据并计算统计信息
val marketIds = groups.keys.toList()
val markets = marketService.getMarkets(marketIds)
val list = marketIds.map { marketId ->
val marketOrders = groups[marketId] ?: mutableListOf()
@@ -659,9 +707,25 @@ class CopyTradingStatisticsService(
?: return Result.failure(IllegalArgumentException("跟单关系不存在: ${request.copyTradingId}"))
// 2. 获取所有卖出记录
val sellRecords = sellMatchRecordRepository.findByCopyTradingId(request.copyTradingId)
var sellRecords = sellMatchRecordRepository.findByCopyTradingId(request.copyTradingId)
// 3. 按市场ID分组
// 3. 批量获取市场信息(用于筛选)
val allMarketIds = sellRecords.map { it.marketId }.distinct()
val markets = marketService.getMarkets(allMarketIds)
// 4. 筛选
if (!request.marketId.isNullOrBlank()) {
// marketId 支持模糊匹配
sellRecords = sellRecords.filter { it.marketId.contains(request.marketId!!, ignoreCase = true) }
}
if (!request.marketTitle.isNullOrBlank()) {
// marketTitle 关键字筛选
sellRecords = sellRecords.filter { record ->
val market = markets[record.marketId]
market?.title?.contains(request.marketTitle!!, ignoreCase = true) == true
}
}
// 5. 按市场ID分组
val groups = mutableMapOf<String, MutableList<SellMatchRecord>>()
sellRecords.forEach { record ->
val marketId = record.marketId
@@ -673,7 +737,6 @@ class CopyTradingStatisticsService(
// 4. 转换为分组数据并计算统计信息
val marketIds = groups.keys.toList()
val markets = marketService.getMarkets(marketIds)
val list = marketIds.map { marketId ->
val marketRecords = groups[marketId] ?: mutableListOf()
+1
View File
@@ -1089,6 +1089,7 @@
"price": "价格",
"amount": "金额",
"filterMarketId": "筛选市场ID",
"filterMarketTitle": "筛选市场标题",
"filterSide": "筛选方向",
"filterStatus": "筛选状态",
"filterSellOrderId": "筛选卖出订单ID",
@@ -25,19 +25,44 @@ const BuyOrdersTab: React.FC<BuyOrdersTabProps> = ({ copyTradingId, active = fal
const [limit, setLimit] = useState(20)
const [filters, setFilters] = useState<{
marketId?: string
side?: string
marketTitle?: string
status?: string
}>({})
const [groupByMarket, setGroupByMarket] = useState(false) // 是否按市场分组
// 从 localStorage 读取用户分组偏好,如果没有则默认为 false
const [groupByMarket, setGroupByMarket] = useState(() => {
const savedPreference = localStorage.getItem('copyTradingOrders_groupByMarket')
return savedPreference === 'true'
})
const [expandedMarkets, setExpandedMarkets] = useState<Set<string>>(new Set()) // 展开的市场ID集合
const [groupedOrders, setGroupedOrders] = useState<MarketOrderGroup[]>([]) // 分组数据(从后端获取)
const [groupedTotal, setGroupedTotal] = useState(0) // 分组总数(市场数量)
const handleMarketTitleChange = (value: string) => {
setFilters({ ...filters, marketTitle: value || undefined })
}
// 切换分组模式时,保存用户偏好到 localStorage
const handleToggleGroupByMarket = (checked: boolean) => {
setGroupByMarket(checked)
localStorage.setItem('copyTradingOrders_groupByMarket', String(checked))
}
useEffect(() => {
if (copyTradingId && active) {
fetchOrders()
}
}, [copyTradingId, active, page, limit, filters, groupByMarket])
}, [copyTradingId, active, page, limit, filters.marketId, filters.status, groupByMarket])
// 防抖搜索 - marketTitle 和 marketId 变化时延迟0.5秒再搜索
useEffect(() => {
if (!copyTradingId || !active) return
const timer = setTimeout(() => {
fetchOrders()
}, 500) // 0.5秒延迟
return () => clearTimeout(timer)
}, [filters.marketTitle])
const fetchOrders = async () => {
if (!copyTradingId) return
@@ -45,12 +70,14 @@ const BuyOrdersTab: React.FC<BuyOrdersTabProps> = ({ copyTradingId, active = fal
setLoading(true)
try {
if (groupByMarket) {
// 调用分组接口
// 调用分组接口(支持市场筛选)
const request: MarketGroupedOrdersRequest = {
copyTradingId: parseInt(copyTradingId),
type: 'buy',
page,
limit
limit,
marketId: filters.marketId,
marketTitle: filters.marketTitle
}
const response = await apiService.orderTracking.listGroupedByMarket(request)
@@ -123,7 +150,7 @@ const BuyOrdersTab: React.FC<BuyOrdersTabProps> = ({ copyTradingId, active = fal
}
}
const columns = [
const columns = [
{
title: t('copyTradingOrders.orderId') || '订单ID',
dataIndex: 'orderId',
@@ -208,16 +235,6 @@ const BuyOrdersTab: React.FC<BuyOrdersTabProps> = ({ copyTradingId, active = fal
)
}
},
{
title: t('copyTradingOrders.side') || '方向',
dataIndex: 'side',
key: 'side',
width: isMobile ? 60 : 80,
render: (side: string) => {
const displaySide = side === '0' ? 'YES' : side === '1' ? 'NO' : side
return <Tag style={{ fontSize: isMobile ? 11 : 12 }}>{displaySide}</Tag>
}
},
{
title: t('copyTradingOrders.buyQuantity') || '买入数量',
dataIndex: 'quantity',
@@ -400,7 +417,6 @@ const BuyOrdersTab: React.FC<BuyOrdersTabProps> = ({ copyTradingId, active = fal
minute: '2-digit'
})
const amount = (parseFloat(order.quantity) * parseFloat(order.price)).toString()
const displaySide = order.side === '0' ? 'YES' : order.side === '1' ? 'NO' : order.side
return (
<Card
@@ -436,7 +452,6 @@ const BuyOrdersTab: React.FC<BuyOrdersTabProps> = ({ copyTradingId, active = fal
)}
</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '6px', alignItems: 'center' }}>
<Tag style={{ fontSize: '11px' }}>{displaySide}</Tag>
{getStatusTag(order.status)}
</div>
</div>
@@ -485,18 +500,17 @@ const BuyOrdersTab: React.FC<BuyOrdersTabProps> = ({ copyTradingId, active = fal
) : (
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
{orders.map((order) => {
const date = new Date(order.createdAt)
const formattedDate = date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
})
const amount = (parseFloat(order.quantity) * parseFloat(order.price)).toString()
const displaySide = order.side === '0' ? 'YES' : order.side === '1' ? 'NO' : order.side
const date = new Date(order.createdAt)
const formattedDate = date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
})
const amount = (parseFloat(order.quantity) * parseFloat(order.price)).toString()
return (
return (
<Card
key={order.orderId}
style={{
@@ -529,7 +543,6 @@ const BuyOrdersTab: React.FC<BuyOrdersTabProps> = ({ copyTradingId, active = fal
)}
</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '6px', alignItems: 'center' }}>
<Tag>{displaySide}</Tag>
{getStatusTag(order.status)}
</div>
</div>
@@ -633,23 +646,20 @@ const BuyOrdersTab: React.FC<BuyOrdersTabProps> = ({ copyTradingId, active = fal
<div>
<div style={{ marginBottom: 16, display: 'flex', gap: 16, flexWrap: 'wrap', alignItems: 'center' }}>
<Input
placeholder={t('copyTradingOrders.filterMarketId') || '筛选市场ID'}
placeholder={t('copyTradingOrders.filterMarketId') || '筛选市场ID(支持模糊匹配)'}
allowClear
style={{ width: isMobile ? '100%' : 200 }}
value={filters.marketId}
onChange={(e) => setFilters({ ...filters, marketId: e.target.value || undefined })}
/>
<Select
placeholder={t('copyTradingOrders.filterSide') || '筛选方向'}
<Input
placeholder={t('copyTradingOrders.filterMarketTitle') || '筛选市场标题'}
allowClear
style={{ width: isMobile ? '100%' : 150 }}
value={filters.side}
onChange={(value) => setFilters({ ...filters, side: value || undefined })}
>
<Option value="0">YES</Option>
<Option value="1">NO</Option>
</Select>
style={{ width: isMobile ? '100%' : 200 }}
value={filters.marketTitle}
onChange={(e) => handleMarketTitleChange(e.target.value)}
/>
<Select
placeholder={t('copyTradingOrders.filterStatus') || '筛选状态'}
@@ -669,7 +679,7 @@ const BuyOrdersTab: React.FC<BuyOrdersTabProps> = ({ copyTradingId, active = fal
</span>
<Switch
checked={groupByMarket}
onChange={setGroupByMarket}
onChange={handleToggleGroupByMarket}
checkedChildren={<AppstoreOutlined />}
unCheckedChildren={<UnorderedListOutlined />}
/>
@@ -24,13 +24,29 @@ const MatchedOrdersTab: React.FC<MatchedOrdersTabProps> = ({ copyTradingId, acti
const [filters, setFilters] = useState<{
sellOrderId?: string
buyOrderId?: string
marketTitle?: string
}>({})
const handleMarketTitleChange = (value: string) => {
setFilters({ ...filters, marketTitle: value || undefined })
}
useEffect(() => {
if (copyTradingId && active) {
fetchOrders()
}
}, [copyTradingId, active, page, limit, filters])
}, [copyTradingId, active, page, limit])
// 防抖搜索 - marketTitle 和 orderId 变化时延迟0.5秒再搜索
useEffect(() => {
if (!copyTradingId || !active) return
const timer = setTimeout(() => {
fetchOrders()
}, 500) // 0.5秒延迟
return () => clearTimeout(timer)
}, [filters.marketTitle, filters.buyOrderId, filters.sellOrderId])
const fetchOrders = async () => {
if (!copyTradingId) return
@@ -193,6 +209,14 @@ const MatchedOrdersTab: React.FC<MatchedOrdersTabProps> = ({ copyTradingId, acti
return (
<div>
<div style={{ marginBottom: 16, display: 'flex', gap: 16, flexWrap: 'wrap' }}>
<Input
placeholder={t('copyTradingOrders.filterMarketTitle') || '筛选市场标题'}
allowClear
style={{ width: isMobile ? '100%' : 200 }}
value={filters.marketTitle}
onChange={(e) => handleMarketTitleChange(e.target.value)}
/>
<Input
placeholder={t('copyTradingOrders.filterSellOrderId') || '筛选卖出订单ID'}
allowClear
@@ -25,18 +25,44 @@ const SellOrdersTab: React.FC<SellOrdersTabProps> = ({ copyTradingId, active = f
const [limit, setLimit] = useState(20)
const [filters, setFilters] = useState<{
marketId?: string
side?: string
marketTitle?: string
status?: string
}>({})
const [groupByMarket, setGroupByMarket] = useState(false) // 是否按市场分组
// 从 localStorage 读取用户分组偏好,如果没有则默认为 false
const [groupByMarket, setGroupByMarket] = useState(() => {
const savedPreference = localStorage.getItem('copyTradingOrders_groupByMarket_sell')
return savedPreference === 'true'
})
const [expandedMarkets, setExpandedMarkets] = useState<Set<string>>(new Set()) // 展开的市场ID集合
const [groupedOrders, setGroupedOrders] = useState<MarketOrderGroup[]>([]) // 分组数据(从后端获取)
const [groupedTotal, setGroupedTotal] = useState(0) // 分组总数(市场数量)
const handleMarketTitleChange = (value: string) => {
setFilters({ ...filters, marketTitle: value || undefined })
}
// 切换分组模式时,保存用户偏好到 localStorage
const handleToggleGroupByMarket = (checked: boolean) => {
setGroupByMarket(checked)
localStorage.setItem('copyTradingOrders_groupByMarket_sell', String(checked))
}
useEffect(() => {
if (copyTradingId && active) {
fetchOrders()
}
}, [copyTradingId, active, page, limit, filters, groupByMarket])
}, [copyTradingId, active, page, limit, filters.marketId, filters.status, groupByMarket])
// 防抖搜索 - marketTitle 变化时延迟0.5秒再搜索
useEffect(() => {
if (!copyTradingId || !active) return
const timer = setTimeout(() => {
fetchOrders()
}, 500) // 0.5秒延迟
return () => clearTimeout(timer)
}, [filters.marketTitle])
const fetchOrders = async () => {
if (!copyTradingId) return
@@ -49,7 +75,9 @@ const SellOrdersTab: React.FC<SellOrdersTabProps> = ({ copyTradingId, active = f
copyTradingId: parseInt(copyTradingId),
type: 'sell',
page,
limit
limit,
marketId: filters.marketId,
marketTitle: filters.marketTitle
}
const response = await apiService.orderTracking.listGroupedByMarket(request)
@@ -204,16 +232,6 @@ const SellOrdersTab: React.FC<SellOrdersTabProps> = ({ copyTradingId, active = f
)
}
},
{
title: t('copyTradingOrders.side') || '方向',
dataIndex: 'side',
key: 'side',
width: isMobile ? 60 : 80,
render: (side: string) => {
const displaySide = side === '0' ? 'YES' : side === '1' ? 'NO' : side
return <Tag style={{ fontSize: isMobile ? 11 : 12 }}>{displaySide}</Tag>
}
},
{
title: t('copyTradingOrders.sellQuantity') || '卖出数量',
dataIndex: 'quantity',
@@ -378,7 +396,6 @@ const SellOrdersTab: React.FC<SellOrdersTabProps> = ({ copyTradingId, active = f
minute: '2-digit'
})
const amount = (parseFloat(order.quantity) * parseFloat(order.price)).toString()
const displaySide = order.side === '0' ? 'YES' : order.side === '1' ? 'NO' : order.side
return (
<Card
@@ -413,9 +430,6 @@ const SellOrdersTab: React.FC<SellOrdersTabProps> = ({ copyTradingId, active = f
/>
)}
</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '6px', alignItems: 'center' }}>
<Tag style={{ fontSize: '11px' }}>{displaySide}</Tag>
</div>
</div>
<div style={{ fontSize: '12px', color: '#666' }}>
@@ -473,7 +487,6 @@ const SellOrdersTab: React.FC<SellOrdersTabProps> = ({ copyTradingId, active = f
minute: '2-digit'
})
const amount = (parseFloat(order.quantity) * parseFloat(order.price)).toString()
const displaySide = order.side === '0' ? 'YES' : order.side === '1' ? 'NO' : order.side
return (
<Card
@@ -507,9 +520,6 @@ const SellOrdersTab: React.FC<SellOrdersTabProps> = ({ copyTradingId, active = f
/>
)}
</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '6px', alignItems: 'center' }}>
<Tag>{displaySide}</Tag>
</div>
</div>
<Divider style={{ margin: '12px 0' }} />
@@ -622,17 +632,24 @@ const SellOrdersTab: React.FC<SellOrdersTabProps> = ({ copyTradingId, active = f
onChange={(e) => setFilters({ ...filters, marketId: e.target.value || undefined })}
/>
<Input
placeholder={t('copyTradingOrders.filterMarketTitle') || '筛选市场标题'}
allowClear
style={{ width: isMobile ? '100%' : 200 }}
value={filters.marketTitle}
onChange={(e) => handleMarketTitleChange(e.target.value)}
/>
<Select
placeholder={t('copyTradingOrders.filterSide') || '筛选方向'}
placeholder={t('copyTradingOrders.filterStatus') || '筛选状态'}
allowClear
style={{ width: isMobile ? '100%' : 150 }}
value={filters.side}
onChange={(value) => setFilters({ ...filters, side: value || undefined })}
value={filters.status}
onChange={(value) => setFilters({ ...filters, status: value || undefined })}
>
<Option value="0">YES</Option>
<Option value="1">NO</Option>
<Option value="YES">YES</Option>
<Option value="NO">NO</Option>
<Option value="filled">{t('copyTradingOrders.statusFilled') || '未成交'}</Option>
<Option value="partially_matched">{t('copyTradingOrders.statusPartiallyMatched') || '部分成交'}</Option>
<Option value="fully_matched">{t('copyTradingOrders.statusFullyMatched') || '完全成交'}</Option>
</Select>
<Space>
@@ -641,7 +658,7 @@ const SellOrdersTab: React.FC<SellOrdersTabProps> = ({ copyTradingId, active = f
</span>
<Switch
checked={groupByMarket}
onChange={setGroupByMarket}
onChange={handleToggleGroupByMarket}
checkedChildren={<AppstoreOutlined />}
unCheckedChildren={<UnorderedListOutlined />}
/>
+4 -1
View File
@@ -670,6 +670,7 @@ export interface SellOrderInfo {
price: string
amount: string
realizedPnl: string
status?: string // 卖出状态(filled, partially_matched, fully_matched
createdAt: number
}
@@ -710,7 +711,7 @@ export interface OrderTrackingRequest {
page?: number
limit?: number
marketId?: string
side?: string
marketTitle?: string
status?: string
sellOrderId?: string
buyOrderId?: string
@@ -724,6 +725,8 @@ export interface MarketGroupedOrdersRequest {
type: 'buy' | 'sell'
page?: number
limit?: number
marketId?: string
marketTitle?: string
}
/**