fix: 修复跟单配置更新时清空可选字段无法保存的问题
- 修复价格区间(minPrice/maxPrice)清空后无法保存的问题 - 修复最大仓位数量(maxPositionCount)清空后无法保存的问题 - 修复市场截止时间(maxMarketEndDate)清空后无法保存的问题 - 修复其他可选字段(minOrderDepth/maxSpread/maxPositionValue)清空后无法保存的问题 - 修复截止时间输入框删除后失去焦点自动填充1的问题 前端:清空字段时传空字符串或-1标记,让后端识别为清空操作 后端:处理空字符串和-1标记,正确设置为null以清空字段
This commit is contained in:
+72
-7
@@ -10,6 +10,7 @@ import com.wrbug.polymarketbot.repository.CopyTradingTemplateRepository
|
||||
import com.wrbug.polymarketbot.repository.LeaderRepository
|
||||
import com.wrbug.polymarketbot.service.copytrading.monitor.CopyTradingMonitorService
|
||||
import com.google.gson.Gson
|
||||
import com.wrbug.polymarketbot.util.IllegalBigDecimal
|
||||
import com.wrbug.polymarketbot.util.JsonUtils
|
||||
import com.wrbug.polymarketbot.util.toSafeBigDecimal
|
||||
import org.slf4j.LoggerFactory
|
||||
@@ -211,12 +212,67 @@ class CopyTradingService(
|
||||
websocketReconnectInterval = request.websocketReconnectInterval ?: copyTrading.websocketReconnectInterval,
|
||||
websocketMaxRetries = request.websocketMaxRetries ?: copyTrading.websocketMaxRetries,
|
||||
supportSell = request.supportSell ?: copyTrading.supportSell,
|
||||
minOrderDepth = request.minOrderDepth?.toSafeBigDecimal() ?: copyTrading.minOrderDepth,
|
||||
maxSpread = request.maxSpread?.toSafeBigDecimal() ?: copyTrading.maxSpread,
|
||||
minPrice = request.minPrice?.toSafeBigDecimal() ?: copyTrading.minPrice,
|
||||
maxPrice = request.maxPrice?.toSafeBigDecimal() ?: copyTrading.maxPrice,
|
||||
maxPositionValue = request.maxPositionValue?.toSafeBigDecimal() ?: copyTrading.maxPositionValue,
|
||||
maxPositionCount = request.maxPositionCount ?: copyTrading.maxPositionCount,
|
||||
// 处理可选字段:空字符串表示要清空(设置为 null),null 表示不更新,转换失败保留旧值
|
||||
minOrderDepth = if (request.minOrderDepth != null) {
|
||||
if (request.minOrderDepth.isBlank()) {
|
||||
null
|
||||
} else {
|
||||
val converted = request.minOrderDepth.toSafeBigDecimal()
|
||||
if (converted == IllegalBigDecimal) copyTrading.minOrderDepth else converted
|
||||
}
|
||||
} else {
|
||||
copyTrading.minOrderDepth
|
||||
},
|
||||
maxSpread = if (request.maxSpread != null) {
|
||||
if (request.maxSpread.isBlank()) {
|
||||
null
|
||||
} else {
|
||||
val converted = request.maxSpread.toSafeBigDecimal()
|
||||
if (converted == IllegalBigDecimal) copyTrading.maxSpread else converted
|
||||
}
|
||||
} else {
|
||||
copyTrading.maxSpread
|
||||
},
|
||||
minPrice = if (request.minPrice != null) {
|
||||
if (request.minPrice.isBlank()) {
|
||||
null
|
||||
} else {
|
||||
val converted = request.minPrice.toSafeBigDecimal()
|
||||
if (converted == IllegalBigDecimal) copyTrading.minPrice else converted
|
||||
}
|
||||
} else {
|
||||
copyTrading.minPrice
|
||||
},
|
||||
maxPrice = if (request.maxPrice != null) {
|
||||
if (request.maxPrice.isBlank()) {
|
||||
null
|
||||
} else {
|
||||
val converted = request.maxPrice.toSafeBigDecimal()
|
||||
if (converted == IllegalBigDecimal) copyTrading.maxPrice else converted
|
||||
}
|
||||
} else {
|
||||
copyTrading.maxPrice
|
||||
},
|
||||
maxPositionValue = if (request.maxPositionValue != null) {
|
||||
if (request.maxPositionValue.isBlank()) {
|
||||
null
|
||||
} else {
|
||||
val converted = request.maxPositionValue.toSafeBigDecimal()
|
||||
if (converted == IllegalBigDecimal) copyTrading.maxPositionValue else converted
|
||||
}
|
||||
} else {
|
||||
copyTrading.maxPositionValue
|
||||
},
|
||||
// 处理 maxPositionCount:-1 表示要清空(设置为 null),null 表示不更新
|
||||
maxPositionCount = if (request.maxPositionCount != null) {
|
||||
if (request.maxPositionCount == -1) {
|
||||
null
|
||||
} else {
|
||||
request.maxPositionCount
|
||||
}
|
||||
} else {
|
||||
copyTrading.maxPositionCount
|
||||
},
|
||||
keywordFilterMode = request.keywordFilterMode ?: copyTrading.keywordFilterMode,
|
||||
keywords = if (request.keywords != null) {
|
||||
convertKeywordsToJson(request.keywords)
|
||||
@@ -227,7 +283,16 @@ class CopyTradingService(
|
||||
},
|
||||
configName = configName,
|
||||
pushFailedOrders = request.pushFailedOrders ?: copyTrading.pushFailedOrders,
|
||||
maxMarketEndDate = request.maxMarketEndDate ?: copyTrading.maxMarketEndDate,
|
||||
// 处理 maxMarketEndDate:-1 表示要清空(设置为 null),null 表示不更新
|
||||
maxMarketEndDate = if (request.maxMarketEndDate != null) {
|
||||
if (request.maxMarketEndDate == -1L) {
|
||||
null
|
||||
} else {
|
||||
request.maxMarketEndDate
|
||||
}
|
||||
} else {
|
||||
copyTrading.maxMarketEndDate
|
||||
},
|
||||
updatedAt = System.currentTimeMillis()
|
||||
)
|
||||
|
||||
|
||||
@@ -168,12 +168,17 @@ const EditModal: React.FC<EditModalProps> = ({
|
||||
}
|
||||
|
||||
// 计算市场截止时间(毫秒)
|
||||
// 如果用户清空了,传 -1 表示要清空(后端会识别并设置为 null)
|
||||
let maxMarketEndDate: number | undefined
|
||||
if (maxMarketEndDateValue !== undefined && maxMarketEndDateValue > 0) {
|
||||
if (maxMarketEndDateValue !== undefined && maxMarketEndDateValue !== null && maxMarketEndDateValue > 0) {
|
||||
const multiplier = maxMarketEndDateUnit === 'HOUR'
|
||||
? 60 * 60 * 1000 // 小时转毫秒
|
||||
: 24 * 60 * 60 * 1000 // 天转毫秒
|
||||
maxMarketEndDate = maxMarketEndDateValue * multiplier
|
||||
} else {
|
||||
// 如果值为 null/undefined/0/负数,传 -1 表示要清空
|
||||
// 这样无论之前是否有值,清空后都会设置为 null
|
||||
maxMarketEndDate = -1
|
||||
}
|
||||
|
||||
setLoading(true)
|
||||
@@ -195,12 +200,14 @@ const EditModal: React.FC<EditModalProps> = ({
|
||||
websocketReconnectInterval: values.websocketReconnectInterval,
|
||||
websocketMaxRetries: values.websocketMaxRetries,
|
||||
supportSell: values.supportSell,
|
||||
minOrderDepth: values.minOrderDepth?.toString(),
|
||||
maxSpread: values.maxSpread?.toString(),
|
||||
minPrice: values.minPrice?.toString(),
|
||||
maxPrice: values.maxPrice?.toString(),
|
||||
maxPositionValue: values.maxPositionValue?.toString(),
|
||||
maxPositionCount: values.maxPositionCount,
|
||||
// 对于可选字段,始终发送(即使为空也发送空字符串,让后端知道要清空)
|
||||
minOrderDepth: values.minOrderDepth != null ? values.minOrderDepth.toString() : '',
|
||||
maxSpread: values.maxSpread != null ? values.maxSpread.toString() : '',
|
||||
minPrice: values.minPrice != null ? values.minPrice.toString() : '',
|
||||
maxPrice: values.maxPrice != null ? values.maxPrice.toString() : '',
|
||||
maxPositionValue: values.maxPositionValue != null ? values.maxPositionValue.toString() : '',
|
||||
// 对于 maxPositionCount,如果值为 null/undefined,传 -1 表示要清空(后端会识别并设置为 null)
|
||||
maxPositionCount: values.maxPositionCount != null ? values.maxPositionCount : -1,
|
||||
keywordFilterMode: values.keywordFilterMode || 'DISABLED',
|
||||
keywords: (values.keywordFilterMode === 'WHITELIST' || values.keywordFilterMode === 'BLACKLIST')
|
||||
? keywords
|
||||
@@ -722,18 +729,35 @@ const EditModal: React.FC<EditModalProps> = ({
|
||||
>
|
||||
<Input.Group compact style={{ display: 'flex' }}>
|
||||
<InputNumber
|
||||
min={1}
|
||||
min={0}
|
||||
max={9999}
|
||||
step={1}
|
||||
precision={0}
|
||||
value={maxMarketEndDateValue}
|
||||
onChange={(value) => setMaxMarketEndDateValue(value !== null && value !== undefined ? Math.floor(value) : undefined)}
|
||||
onChange={(value) => {
|
||||
// 允许设置为 null 或 undefined(清空)
|
||||
if (value === null || value === undefined) {
|
||||
setMaxMarketEndDateValue(undefined)
|
||||
} else {
|
||||
const num = Math.floor(value)
|
||||
// 如果值为 0,也设置为 undefined(表示清空)
|
||||
setMaxMarketEndDateValue(num > 0 ? num : undefined)
|
||||
}
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
// 失去焦点时,如果值为 0 或空,设置为 undefined
|
||||
const input = e.target as HTMLInputElement
|
||||
const value = input.value
|
||||
if (!value || value === '0') {
|
||||
setMaxMarketEndDateValue(undefined)
|
||||
}
|
||||
}}
|
||||
style={{ width: '60%' }}
|
||||
placeholder={t('copyTradingEdit.maxMarketEndDatePlaceholder') || '输入时间值(可选)'}
|
||||
parser={(value) => {
|
||||
if (!value) return 0
|
||||
if (!value) return ''
|
||||
const num = parseInt(value.replace(/\D/g, ''), 10)
|
||||
return isNaN(num) ? 0 : num
|
||||
return isNaN(num) ? '' : num.toString()
|
||||
}}
|
||||
formatter={(value) => {
|
||||
if (!value && value !== 0) return ''
|
||||
|
||||
Reference in New Issue
Block a user