补全过滤入口与直接兑换,优化兑换分类和 WSS 建连
- GUI 接线 Exchange 绑定:新增「直接兑换」按钮,结果带 category/message 并进入结果面板 - 补 -max-price/-min-left(CLI 与 GUI 设置),Target 的价格与库存过滤不再悬空 - 删除死代码 sendUpdateUserInfo 及其请求结构体(浏览器流程不含该帧) - ClassifyExchange 改为多路判定:合并 msg/actPreCondition/exchangeInfo 文案,status=200 且有 orderId 视为成功,新增 condition 分类(precondition 门禁) - WSS 建连改为锁外 dial、锁内注册,同 uid 并发调用共享一次握手 - 默认传输层统一为 http(CLI/GUI/README),.gitignore 忽略 .DS_Store - 同步 Wails 依赖升级(2.12.0 -> 2.15.0)并重新生成前端绑定
This commit is contained in:
+63
-3
@@ -31,9 +31,11 @@ import {
|
||||
Square,
|
||||
Settings,
|
||||
Trash2,
|
||||
Zap,
|
||||
} from 'lucide-react'
|
||||
import {
|
||||
DefaultConfig,
|
||||
Exchange,
|
||||
GetLogs,
|
||||
GetRecords,
|
||||
IsRunning,
|
||||
@@ -56,6 +58,8 @@ type UiConfig = {
|
||||
pid: number
|
||||
name: string
|
||||
targetText: string
|
||||
maxPrice: number
|
||||
minLeft: number
|
||||
cookieText: string
|
||||
selectedAccountLines: number[]
|
||||
loops: number
|
||||
@@ -167,6 +171,14 @@ type ExchangeResp = {
|
||||
actPreCondition?: ActPreCondition
|
||||
}
|
||||
|
||||
type ExchangeResult = {
|
||||
uid: number
|
||||
resp?: ExchangeResp
|
||||
category?: string
|
||||
message?: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
type MonitorResult = {
|
||||
key?: string
|
||||
loop?: number
|
||||
@@ -300,6 +312,7 @@ function categoryTag(category?: string): ReactNode {
|
||||
already_done: { color: 'purple', label: '已兑' },
|
||||
off_shelf: { color: 'error', label: '下架' },
|
||||
sold_out: { color: 'error', label: '抢完' },
|
||||
condition: { color: 'geekblue', label: '条件' },
|
||||
failed: { color: 'warning', label: '失败' },
|
||||
error: { color: 'error', label: '异常' },
|
||||
}
|
||||
@@ -399,12 +412,14 @@ function newCookieID(): string {
|
||||
|
||||
function pickConfig(values: Partial<UiConfig>): UiConfig {
|
||||
return {
|
||||
transport: values.transport || 'wss',
|
||||
transport: values.transport || 'http',
|
||||
wssHost: values.wssHost || '',
|
||||
sid: Number(values.sid || 0),
|
||||
pid: Number(values.pid || 0),
|
||||
name: values.name || '',
|
||||
targetText: values.targetText || '',
|
||||
maxPrice: Number(values.maxPrice || 0),
|
||||
minLeft: Number(values.minLeft || 0),
|
||||
cookieText: values.cookieText || '',
|
||||
selectedAccountLines: values.selectedAccountLines || [],
|
||||
loops: Number(values.loops || 1),
|
||||
@@ -596,7 +611,9 @@ export default function Dashboard() {
|
||||
const errorCount = useMemo(
|
||||
() =>
|
||||
results.filter((item) =>
|
||||
['error', 'failed', 'not_enough', 'off_shelf', 'sold_out'].includes(item.category || ''),
|
||||
['error', 'failed', 'not_enough', 'off_shelf', 'sold_out', 'condition'].includes(
|
||||
item.category || '',
|
||||
),
|
||||
).length,
|
||||
[results],
|
||||
)
|
||||
@@ -827,6 +844,8 @@ export default function Dashboard() {
|
||||
pid: values.pid,
|
||||
name: values.name,
|
||||
targetText: values.targetText,
|
||||
maxPrice: values.maxPrice,
|
||||
minLeft: values.minLeft,
|
||||
loops: values.loops,
|
||||
delayMs: values.delayMs,
|
||||
concurrency: values.concurrency,
|
||||
@@ -881,6 +900,33 @@ export default function Dashboard() {
|
||||
})
|
||||
}
|
||||
|
||||
const directExchange = () => {
|
||||
const values = config()
|
||||
if (Number(values.pid || 0) <= 0) {
|
||||
message.warning('请先在左侧商品列表中选择要兑换的商品')
|
||||
return undefined
|
||||
}
|
||||
return runAction(
|
||||
'exchange',
|
||||
() => Exchange(values),
|
||||
(data) => {
|
||||
const items = (data || []) as ExchangeResult[]
|
||||
setResults(
|
||||
items.map((item, index) => ({
|
||||
key: `exchange-${item.uid}-${index}-${Date.now()}`,
|
||||
uid: item.uid,
|
||||
action: 'exchange',
|
||||
category: item.category || (item.error ? 'error' : 'failed'),
|
||||
message: item.message || item.error || item.resp?.msg || '',
|
||||
exchange: item.resp,
|
||||
})),
|
||||
)
|
||||
const success = items.filter((item) => item.category === 'success').length
|
||||
message.info(`直接兑换:成功 ${success}/${items.length}`)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
const selectAllAccounts = () => {
|
||||
setSelectedAccountLines(validAccounts.map((item) => item.line))
|
||||
}
|
||||
@@ -1180,7 +1226,7 @@ export default function Dashboard() {
|
||||
</div>
|
||||
<CountdownBadge countdown={scheduleCountdown} now={now} running={running} />
|
||||
<Space size={12}>
|
||||
<Tag>{String(watchedTransport || 'wss').toUpperCase()}</Tag>
|
||||
<Tag>{String(watchedTransport || 'http').toUpperCase()}</Tag>
|
||||
<Button icon={<Settings size={16} />} onClick={() => setSettingsOpen(true)}>
|
||||
设置
|
||||
</Button>
|
||||
@@ -1225,6 +1271,14 @@ export default function Dashboard() {
|
||||
>
|
||||
开启定时
|
||||
</Button>
|
||||
<Button
|
||||
icon={<Zap size={16} />}
|
||||
loading={loading === 'exchange'}
|
||||
disabled={running || validAccounts.length === 0}
|
||||
onClick={directExchange}
|
||||
>
|
||||
直接兑换
|
||||
</Button>
|
||||
<Button
|
||||
icon={<ClipboardPaste size={16} />}
|
||||
loading={loading === 'clipboard'}
|
||||
@@ -1456,6 +1510,12 @@ export default function Dashboard() {
|
||||
<Form.Item name="pid" label="PID">
|
||||
<InputNumber min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item name="maxPrice" label="最高积分">
|
||||
<InputNumber min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item name="minLeft" label="最少库存">
|
||||
<InputNumber min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item name="loops" label="次数">
|
||||
<InputNumber min={1} max={9999} />
|
||||
</Form.Item>
|
||||
|
||||
Reference in New Issue
Block a user