feat:自动补货/手动采购逻辑修改:批量获取-》打包-》获取Token列表
This commit is contained in:
@@ -572,6 +572,7 @@ export interface RockConfig {
|
||||
bearer_token: string;
|
||||
username: string;
|
||||
points: number;
|
||||
black_token_cost: number;
|
||||
min_points_warning: number;
|
||||
token_warning_stock: number;
|
||||
auto_purchase_enabled: boolean;
|
||||
@@ -594,15 +595,28 @@ export interface RockStats {
|
||||
auto_purchase_enabled: boolean;
|
||||
username: string;
|
||||
last_heartbeat_at?: string;
|
||||
last_purchase_error?: string;
|
||||
last_purchase_error_at?: string;
|
||||
}
|
||||
|
||||
export interface RockDashboard {
|
||||
available_black: number;
|
||||
available_blue: number;
|
||||
black_token_cost: number;
|
||||
blue_token_cost: number;
|
||||
cost_updated: boolean;
|
||||
}
|
||||
|
||||
export interface RockTokenItem {
|
||||
id: number;
|
||||
upstream_token_id: string;
|
||||
package_id?: number;
|
||||
token?: string;
|
||||
redeem_code: string;
|
||||
color: string;
|
||||
region: string;
|
||||
status: string;
|
||||
source?: string;
|
||||
assigned_order_no?: string;
|
||||
client_order_no?: string;
|
||||
expected_uid?: string;
|
||||
@@ -616,10 +630,12 @@ export interface RockTokenItem {
|
||||
mismatch_at?: string;
|
||||
mismatch_reason?: string;
|
||||
remark?: string;
|
||||
raw_data?: string;
|
||||
claimed_at?: string;
|
||||
bound_at?: string;
|
||||
redeemed_at?: string;
|
||||
created_at: string;
|
||||
updated_at?: string;
|
||||
}
|
||||
|
||||
export const rockApi = {
|
||||
@@ -635,6 +651,10 @@ export const rockApi = {
|
||||
.then((r) => r.data.data),
|
||||
getStats: () =>
|
||||
request.get("/platform/rock/stats").then((r) => r.data.data as RockStats),
|
||||
refreshDashboard: () =>
|
||||
request
|
||||
.post("/platform/rock/dashboard/refresh")
|
||||
.then((r) => r.data.data as RockDashboard),
|
||||
purchaseTokens: (count = 50) =>
|
||||
request.post("/platform/rock/purchase", { count }).then((r) => r.data.data),
|
||||
listTokens: (params?: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { Button, Form, Modal, Space, message } from 'antd'
|
||||
import { Alert, Button, Form, Modal, Space, message } from 'antd'
|
||||
import { ReloadOutlined, ShoppingCartOutlined } from '@ant-design/icons'
|
||||
import { rockApi, type RockConfig, type RockStats, type RockTokenItem } from '../api'
|
||||
import { PageHeader } from '../components/PageHeader'
|
||||
@@ -12,15 +12,28 @@ import { UidEditModal } from './platformRock/UidEditModal'
|
||||
import { VoucherPreviewModal } from './platformRock/VoucherPreviewModal'
|
||||
import type { UidEditState } from './platformRock/types'
|
||||
|
||||
function prettyRawData(raw?: string) {
|
||||
if (!raw) return '暂无原始数据'
|
||||
try {
|
||||
return JSON.stringify(JSON.parse(raw), null, 2)
|
||||
} catch {
|
||||
return raw
|
||||
}
|
||||
}
|
||||
|
||||
export default function PlatformRock() {
|
||||
const [config, setConfig] = useState<RockConfig | null>(null)
|
||||
const [stats, setStats] = useState<RockStats | null>(null)
|
||||
const [upstreamStock, setUpstreamStock] = useState<number | null>(null)
|
||||
const [loadingStats, setLoadingStats] = useState(false)
|
||||
const [testingConn, setTestingConn] = useState(false)
|
||||
const [savingConfig, setSavingConfig] = useState(false)
|
||||
const [autoPurchaseEnabled, setAutoPurchaseEnabled] = useState(false)
|
||||
const [togglingAutoPurchase, setTogglingAutoPurchase] = useState(false)
|
||||
const [purchasing, setPurchasing] = useState(false)
|
||||
const [purchaseModalOpen, setPurchaseModalOpen] = useState(false)
|
||||
const [purchaseCount, setPurchaseCount] = useState(50)
|
||||
const [rawDataRecord, setRawDataRecord] = useState<RockTokenItem | null>(null)
|
||||
|
||||
// 凭证图片操作状态
|
||||
const [copyingVoucherId, setCopyingVoucherId] = useState<number | null>(null)
|
||||
@@ -43,16 +56,23 @@ export default function PlatformRock() {
|
||||
const loadData = useCallback(async () => {
|
||||
setLoadingStats(true)
|
||||
try {
|
||||
try {
|
||||
const dashboard = await rockApi.refreshDashboard()
|
||||
setUpstreamStock(dashboard.available_black)
|
||||
} catch (e) {
|
||||
setUpstreamStock(null)
|
||||
message.warning('获取上游库存/采购单价失败: ' + (e instanceof Error ? e.message : '未知错误'))
|
||||
}
|
||||
const [cfg, st] = await Promise.all([rockApi.getConfig(), rockApi.getStats()])
|
||||
setConfig(cfg)
|
||||
setStats(st)
|
||||
setAutoPurchaseEnabled(cfg.auto_purchase_enabled)
|
||||
form.setFieldsValue({
|
||||
auto_delivery_enabled: cfg.auto_delivery_enabled,
|
||||
base_url: cfg.base_url,
|
||||
bearer_token: cfg.bearer_token,
|
||||
min_points_warning: cfg.min_points_warning,
|
||||
token_warning_stock: cfg.token_warning_stock,
|
||||
auto_purchase_enabled: cfg.auto_purchase_enabled,
|
||||
auto_purchase_count: cfg.auto_purchase_count,
|
||||
purchase_cooldown_minutes: cfg.purchase_cooldown_minutes,
|
||||
})
|
||||
@@ -114,6 +134,24 @@ export default function PlatformRock() {
|
||||
})
|
||||
}
|
||||
|
||||
// 自动补货开关:切换即保存,避免只改表单值后被刷新回填覆盖
|
||||
const handleToggleAutoPurchase = async (checked: boolean) => {
|
||||
const previous = autoPurchaseEnabled
|
||||
setAutoPurchaseEnabled(checked)
|
||||
setTogglingAutoPurchase(true)
|
||||
try {
|
||||
const updated = await rockApi.updateConfig({ auto_purchase_enabled: checked })
|
||||
setConfig(updated)
|
||||
setAutoPurchaseEnabled(updated.auto_purchase_enabled)
|
||||
message.success(checked ? '自动补货已开启' : '自动补货已关闭')
|
||||
} catch (e) {
|
||||
setAutoPurchaseEnabled(previous)
|
||||
message.error('更新自动补货开关失败: ' + (e instanceof Error ? e.message : '未知错误'))
|
||||
} finally {
|
||||
setTogglingAutoPurchase(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 测试连通性
|
||||
const handleTestConnection = async () => {
|
||||
const bearerToken = form.getFieldValue('bearer_token')
|
||||
@@ -162,6 +200,10 @@ export default function PlatformRock() {
|
||||
message.warning('请输入有效的采购数量')
|
||||
return
|
||||
}
|
||||
if (upstreamStock !== null && count > upstreamStock) {
|
||||
message.warning(`上游可用库存不足:当前 ${upstreamStock} 个,本次需要 ${count} 个`)
|
||||
return
|
||||
}
|
||||
setPurchasing(true)
|
||||
try {
|
||||
const res = await rockApi.purchaseTokens(count)
|
||||
@@ -219,8 +261,9 @@ export default function PlatformRock() {
|
||||
const isStockLow = availableStock <= warningStock
|
||||
const hasMismatch = (stats?.mismatch_stock ?? 0) > 0
|
||||
const upstreamPoints = stats?.upstream_points ?? 0
|
||||
const maxPurchasable = Math.max(0, Math.floor(upstreamPoints / 21))
|
||||
const estimatedCost = (purchaseCount || 0) * 21
|
||||
const tokenCost = config?.black_token_cost && config.black_token_cost > 0 ? config.black_token_cost : 20
|
||||
const maxPurchasable = Math.max(0, Math.floor(upstreamPoints / tokenCost))
|
||||
const estimatedCost = (purchaseCount || 0) * tokenCost
|
||||
const isPointsInsufficient = estimatedCost > upstreamPoints
|
||||
|
||||
return (
|
||||
@@ -249,9 +292,23 @@ export default function PlatformRock() {
|
||||
}
|
||||
/>
|
||||
|
||||
{stats?.last_purchase_error ? (
|
||||
<Alert
|
||||
type="warning"
|
||||
showIcon
|
||||
style={{ marginBottom: 16 }}
|
||||
message="最近一次 Rock 采购/打包未完全成功"
|
||||
description={`${stats.last_purchase_error}${
|
||||
stats.last_purchase_error_at ? `(${stats.last_purchase_error_at})` : ''
|
||||
}`}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{/* 顶部高质感指标卡片 */}
|
||||
<RockMetricCards
|
||||
stats={stats}
|
||||
upstreamStock={upstreamStock}
|
||||
blackTokenCost={tokenCost}
|
||||
availableStock={availableStock}
|
||||
warningStock={warningStock}
|
||||
isStockLow={isStockLow}
|
||||
@@ -265,9 +322,12 @@ export default function PlatformRock() {
|
||||
<RockStrategyCard
|
||||
form={form}
|
||||
autoDelivery={autoDelivery}
|
||||
autoPurchaseEnabled={autoPurchaseEnabled}
|
||||
togglingAutoPurchase={togglingAutoPurchase}
|
||||
testingConn={testingConn}
|
||||
savingConfig={savingConfig}
|
||||
onToggleAutoDelivery={handleToggleAutoDelivery}
|
||||
onToggleAutoPurchase={handleToggleAutoPurchase}
|
||||
onTestConnection={handleTestConnection}
|
||||
onSaveConfig={handleSaveConfig}
|
||||
/>
|
||||
@@ -296,6 +356,7 @@ export default function PlatformRock() {
|
||||
setPreviewVoucherUrl={setPreviewVoucherUrl}
|
||||
setPreviewVoucherOpen={setPreviewVoucherOpen}
|
||||
onEditUid={setUidEdit}
|
||||
onViewRawData={setRawDataRecord}
|
||||
onPageChange={handlePageChange}
|
||||
onReloadData={loadData}
|
||||
onReloadTokens={loadTokens}
|
||||
@@ -311,11 +372,39 @@ export default function PlatformRock() {
|
||||
upstreamPoints={upstreamPoints}
|
||||
estimatedCost={estimatedCost}
|
||||
isPointsInsufficient={isPointsInsufficient}
|
||||
tokenCost={tokenCost}
|
||||
upstreamStock={upstreamStock}
|
||||
onPurchaseCountChange={setPurchaseCount}
|
||||
onCancel={() => setPurchaseModalOpen(false)}
|
||||
onConfirm={handlePurchase}
|
||||
/>
|
||||
|
||||
<Modal
|
||||
open={Boolean(rawDataRecord)}
|
||||
title={rawDataRecord ? `原始数据 · 0666 #${rawDataRecord.upstream_token_id}` : '原始数据'}
|
||||
footer={null}
|
||||
width={760}
|
||||
onCancel={() => setRawDataRecord(null)}
|
||||
>
|
||||
<pre
|
||||
style={{
|
||||
maxHeight: 540,
|
||||
overflow: 'auto',
|
||||
margin: 0,
|
||||
padding: 16,
|
||||
borderRadius: 8,
|
||||
background: '#0f172a',
|
||||
color: '#e2e8f0',
|
||||
fontSize: 12,
|
||||
lineHeight: 1.6,
|
||||
whiteSpace: 'pre-wrap',
|
||||
wordBreak: 'break-all',
|
||||
}}
|
||||
>
|
||||
{prettyRawData(rawDataRecord?.raw_data)}
|
||||
</pre>
|
||||
</Modal>
|
||||
|
||||
<UidEditModal
|
||||
uidEdit={uidEdit}
|
||||
savingUid={savingUid}
|
||||
|
||||
@@ -11,6 +11,8 @@ export interface PurchaseTokenModalProps {
|
||||
upstreamPoints: number
|
||||
estimatedCost: number
|
||||
isPointsInsufficient: boolean
|
||||
tokenCost: number
|
||||
upstreamStock: number | null
|
||||
onPurchaseCountChange: (value: number) => void
|
||||
onCancel: () => void
|
||||
onConfirm: (count: number) => void
|
||||
@@ -25,10 +27,13 @@ export function PurchaseTokenModal({
|
||||
upstreamPoints,
|
||||
estimatedCost,
|
||||
isPointsInsufficient,
|
||||
tokenCost,
|
||||
upstreamStock,
|
||||
onPurchaseCountChange,
|
||||
onCancel,
|
||||
onConfirm,
|
||||
}: PurchaseTokenModalProps) {
|
||||
const isStockInsufficient = upstreamStock !== null && purchaseCount > upstreamStock
|
||||
return (
|
||||
<Modal
|
||||
title={
|
||||
@@ -48,15 +53,16 @@ export function PurchaseTokenModal({
|
||||
type="primary"
|
||||
icon={<ShoppingCartOutlined />}
|
||||
loading={purchasing}
|
||||
disabled={isPointsInsufficient || purchaseCount <= 0}
|
||||
disabled={isPointsInsufficient || isStockInsufficient || purchaseCount <= 0}
|
||||
onClick={() => onConfirm(purchaseCount)}
|
||||
style={{
|
||||
background: isPointsInsufficient
|
||||
? undefined
|
||||
: 'linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%)',
|
||||
background:
|
||||
isPointsInsufficient || isStockInsufficient
|
||||
? undefined
|
||||
: 'linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%)',
|
||||
}}
|
||||
>
|
||||
确认采购 {purchaseCount} 个 ({estimatedCost} 点)
|
||||
确认采购 {purchaseCount} 个 ({estimatedCost.toFixed(2)} 点)
|
||||
</Button>,
|
||||
]}
|
||||
destroyOnClose
|
||||
@@ -88,12 +94,48 @@ export function PurchaseTokenModal({
|
||||
</Col>
|
||||
</Row>
|
||||
<Divider style={{ margin: '10px 0' }} />
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12, color: '#64748b' }}>
|
||||
<span>采购单价:<strong style={{ color: '#0f172a' }}>21 点 / 个</strong></span>
|
||||
<span>最大可采购:<strong style={{ color: '#2563eb' }}>{maxPurchasable} 个</strong></span>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
flexWrap: 'wrap',
|
||||
gap: 8,
|
||||
fontSize: 12,
|
||||
color: '#64748b',
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
采购单价:<strong style={{ color: '#0f172a' }}>{tokenCost.toFixed(2)} 点 / 个</strong>
|
||||
</span>
|
||||
<span>
|
||||
上游可用库存:
|
||||
<strong style={{ color: isStockInsufficient ? '#dc2626' : '#0f172a' }}>
|
||||
{upstreamStock === null ? '未获取' : `${upstreamStock} 个`}
|
||||
</strong>
|
||||
</span>
|
||||
<span>
|
||||
最大可采购:<strong style={{ color: '#2563eb' }}>{maxPurchasable} 个</strong>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 上游库存不足提示 */}
|
||||
{isStockInsufficient && (
|
||||
<div
|
||||
style={{
|
||||
background: '#fef2f2',
|
||||
border: '1px solid #fecaca',
|
||||
borderRadius: 8,
|
||||
padding: '10px 16px',
|
||||
marginBottom: 14,
|
||||
fontSize: 13,
|
||||
color: '#b91c1c',
|
||||
}}
|
||||
>
|
||||
⚠️ 上游可用库存不足:当前 {upstreamStock} 个,本次需要 {purchaseCount} 个,请减少采购数量。
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 采购数量输入 */}
|
||||
<div style={{ marginBottom: 14 }}>
|
||||
<div style={{ fontWeight: 600, marginBottom: 8, color: '#0f172a' }}>
|
||||
@@ -153,7 +195,7 @@ export function PurchaseTokenModal({
|
||||
本次采购消耗积分:
|
||||
</span>
|
||||
<strong style={{ color: isPointsInsufficient ? '#dc2626' : '#16a34a', fontSize: 16 }}>
|
||||
{estimatedCost} 点
|
||||
{estimatedCost.toFixed(2)} 点
|
||||
</strong>
|
||||
</div>
|
||||
<div
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Col, Row, Tag } from 'antd'
|
||||
import {
|
||||
CheckCircleOutlined,
|
||||
CloudServerOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
FireOutlined,
|
||||
ShoppingCartOutlined,
|
||||
@@ -9,6 +10,8 @@ import type { RockStats } from '../../api'
|
||||
|
||||
export interface RockMetricCardsProps {
|
||||
stats: RockStats | null
|
||||
upstreamStock: number | null
|
||||
blackTokenCost: number
|
||||
availableStock: number
|
||||
warningStock: number
|
||||
isStockLow: boolean
|
||||
@@ -20,6 +23,8 @@ export interface RockMetricCardsProps {
|
||||
|
||||
export function RockMetricCards({
|
||||
stats,
|
||||
upstreamStock,
|
||||
blackTokenCost,
|
||||
availableStock,
|
||||
warningStock,
|
||||
isStockLow,
|
||||
@@ -30,7 +35,38 @@ export function RockMetricCards({
|
||||
}: RockMetricCardsProps) {
|
||||
return (
|
||||
<Row gutter={[16, 16]} style={{ marginBottom: 20 }}>
|
||||
<Col xs={24} sm={12} lg={6}>
|
||||
<Col flex="1 1 200px">
|
||||
<div className="metric-card-box">
|
||||
<div className="metric-card-header">
|
||||
<span className="metric-card-title">上游可用库存 (0666.pro)</span>
|
||||
<div className="metric-card-icon" style={{ background: '#e0f2fe', color: '#0284c7' }}>
|
||||
<CloudServerOutlined />
|
||||
</div>
|
||||
</div>
|
||||
<div className="metric-card-value" style={{ color: upstreamStock === null ? '#94a3b8' : '#0369a1' }}>
|
||||
{upstreamStock === null ? '-' : upstreamStock}
|
||||
<span style={{ fontSize: 13, fontWeight: 500, marginLeft: 4, color: '#64748b' }}>个</span>
|
||||
</div>
|
||||
<div className="metric-card-footer">
|
||||
<span>采购单价: {blackTokenCost.toFixed(2)} 点/个</span>
|
||||
{upstreamStock === null ? (
|
||||
<Tag color="warning" style={{ margin: 0, borderRadius: 4 }}>
|
||||
未获取
|
||||
</Tag>
|
||||
) : upstreamStock === 0 ? (
|
||||
<Tag color="error" style={{ margin: 0, borderRadius: 4 }}>
|
||||
无库存
|
||||
</Tag>
|
||||
) : (
|
||||
<Tag color="processing" style={{ margin: 0, borderRadius: 4 }}>
|
||||
实时
|
||||
</Tag>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
|
||||
<Col flex="1 1 200px">
|
||||
<div className="metric-card-box">
|
||||
<div className="metric-card-header">
|
||||
<span className="metric-card-title">可用通用库存 (Available)</span>
|
||||
@@ -45,7 +81,9 @@ export function RockMetricCards({
|
||||
<div className="metric-card-footer">
|
||||
<span>警戒水位: {warningStock} 个</span>
|
||||
{isStockLow ? (
|
||||
<Tag color="error" style={{ margin: 0, borderRadius: 4 }}>库存紧缺</Tag>
|
||||
<Tag color="error" style={{ margin: 0, borderRadius: 4 }}>
|
||||
库存紧缺
|
||||
</Tag>
|
||||
) : (
|
||||
<span style={{ color: '#10b981', fontWeight: 600 }}>储备充足</span>
|
||||
)}
|
||||
@@ -53,7 +91,7 @@ export function RockMetricCards({
|
||||
</div>
|
||||
</Col>
|
||||
|
||||
<Col xs={24} sm={12} lg={6}>
|
||||
<Col flex="1 1 200px">
|
||||
<div className="metric-card-box">
|
||||
<div className="metric-card-header">
|
||||
<span className="metric-card-title">绑定错误阻断 (Mismatch)</span>
|
||||
@@ -68,7 +106,9 @@ export function RockMetricCards({
|
||||
<div className="metric-card-footer">
|
||||
<span>{hasMismatch ? 'UID强一致校验拦截保护' : '暂无异常阻断'}</span>
|
||||
{hasMismatch ? (
|
||||
<Tag color="error" style={{ margin: 0, borderRadius: 4 }}>需核对处理</Tag>
|
||||
<Tag color="error" style={{ margin: 0, borderRadius: 4 }}>
|
||||
需核对处理
|
||||
</Tag>
|
||||
) : (
|
||||
<span style={{ color: '#10b981', fontWeight: 600 }}>状态正常</span>
|
||||
)}
|
||||
@@ -76,7 +116,7 @@ export function RockMetricCards({
|
||||
</div>
|
||||
</Col>
|
||||
|
||||
<Col xs={24} sm={12} lg={6}>
|
||||
<Col flex="1 1 200px">
|
||||
<div className="metric-card-box">
|
||||
<div className="metric-card-header">
|
||||
<span className="metric-card-title">已履约交付 (Redeemed)</span>
|
||||
@@ -95,7 +135,7 @@ export function RockMetricCards({
|
||||
</div>
|
||||
</Col>
|
||||
|
||||
<Col xs={24} sm={12} lg={6}>
|
||||
<Col flex="1 1 200px">
|
||||
<div className="metric-card-box">
|
||||
<div className="metric-card-header">
|
||||
<span className="metric-card-title">0666.pro 账号积分</span>
|
||||
|
||||
@@ -27,9 +27,12 @@ const { Text } = Typography
|
||||
export interface RockStrategyCardProps {
|
||||
form: FormInstance
|
||||
autoDelivery: boolean
|
||||
autoPurchaseEnabled: boolean
|
||||
togglingAutoPurchase: boolean
|
||||
testingConn: boolean
|
||||
savingConfig: boolean
|
||||
onToggleAutoDelivery: (checked: boolean) => void
|
||||
onToggleAutoPurchase: (checked: boolean) => void
|
||||
onTestConnection: () => void
|
||||
onSaveConfig: () => void
|
||||
}
|
||||
@@ -37,9 +40,12 @@ export interface RockStrategyCardProps {
|
||||
export function RockStrategyCard({
|
||||
form,
|
||||
autoDelivery,
|
||||
autoPurchaseEnabled,
|
||||
togglingAutoPurchase,
|
||||
testingConn,
|
||||
savingConfig,
|
||||
onToggleAutoDelivery,
|
||||
onToggleAutoPurchase,
|
||||
onTestConnection,
|
||||
onSaveConfig,
|
||||
}: RockStrategyCardProps) {
|
||||
@@ -227,13 +233,24 @@ export function RockStrategyCard({
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item name="auto_purchase_enabled" label="自动补货触发开关" valuePropName="checked">
|
||||
<Switch checkedChildren="开启自动补货" unCheckedChildren="关闭" />
|
||||
<Form.Item label="自动补货触发开关">
|
||||
<Space direction="vertical" size={2}>
|
||||
<Switch
|
||||
checked={autoPurchaseEnabled}
|
||||
onChange={onToggleAutoPurchase}
|
||||
loading={togglingAutoPurchase}
|
||||
checkedChildren="开启自动补货"
|
||||
unCheckedChildren="关闭"
|
||||
/>
|
||||
<Text type="secondary" style={{ fontSize: 11 }}>
|
||||
切换后立即保存
|
||||
</Text>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item name="auto_purchase_count" label="单次自动补货数量">
|
||||
<InputNumber min={5} max={200} style={{ width: '100%' }} addonAfter="个" />
|
||||
<InputNumber min={1} max={200} style={{ width: '100%' }} addonAfter="个" />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
|
||||
@@ -34,12 +34,12 @@ export function RockTokenFilterBar({
|
||||
<Col xs={24} md={16}>
|
||||
<Space size="middle" wrap>
|
||||
<Input
|
||||
placeholder="搜索 0666 编号 / 提取码 / 订单号 / UID"
|
||||
placeholder="搜索 包ID / 0666 编号 / 提取码 / 兑换码 / 订单号 / UID"
|
||||
prefix={<SearchOutlined style={{ color: '#94a3b8' }} />}
|
||||
value={searchKeyword}
|
||||
onChange={(e) => onSearchKeywordChange(e.target.value)}
|
||||
onPressEnter={onRefresh}
|
||||
style={{ width: 340 }}
|
||||
style={{ width: 400 }}
|
||||
allowClear
|
||||
/>
|
||||
<Radio.Group
|
||||
@@ -72,7 +72,7 @@ export function RockTokenFilterBar({
|
||||
</Col>
|
||||
<Col xs={24} md={8} style={{ textAlign: 'right' }}>
|
||||
<Text type="secondary" style={{ fontSize: 13 }}>
|
||||
共检索到 <strong style={{ color: '#0f172a' }}>{totalTokens}</strong> 条库存记录
|
||||
共检索到 <strong style={{ color: '#0f172a' }}>{totalTokens}</strong> 条 Token 记录
|
||||
</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@@ -18,6 +18,7 @@ export interface RockTokenTableProps {
|
||||
setPreviewVoucherUrl: Dispatch<SetStateAction<string>>
|
||||
setPreviewVoucherOpen: Dispatch<SetStateAction<boolean>>
|
||||
onEditUid: (state: UidEditState) => void
|
||||
onViewRawData: (record: RockTokenItem) => void
|
||||
onPageChange: (page: number, pageSize: number) => void
|
||||
onReloadData: () => void
|
||||
onReloadTokens: () => void
|
||||
@@ -34,6 +35,7 @@ export function RockTokenTable({
|
||||
setPreviewVoucherUrl,
|
||||
setPreviewVoucherOpen,
|
||||
onEditUid,
|
||||
onViewRawData,
|
||||
onPageChange,
|
||||
onReloadData,
|
||||
onReloadTokens,
|
||||
@@ -153,6 +155,7 @@ export function RockTokenTable({
|
||||
onCopyVoucher: handleCopyVoucher,
|
||||
onPreviewVoucher: handlePreviewVoucher,
|
||||
onEditUid,
|
||||
onViewRawData,
|
||||
onResetToken: handleResetToken,
|
||||
onReleaseToken: handleReleaseToken,
|
||||
onUpdateRemark: handleUpdateRemark,
|
||||
@@ -165,14 +168,14 @@ export function RockTokenTable({
|
||||
columns={columns}
|
||||
dataSource={tokens}
|
||||
loading={loadingTokens}
|
||||
scroll={{ x: 1300 }}
|
||||
scroll={{ x: 1700 }}
|
||||
pagination={{
|
||||
current: page,
|
||||
pageSize,
|
||||
total: totalTokens,
|
||||
showSizeChanger: true,
|
||||
pageSizeOptions: ['10', '20', '50', '100'],
|
||||
showTotal: (total) => `共 ${total} 条库存记录`,
|
||||
showTotal: (total) => `共 ${total} 条 Token 记录`,
|
||||
onChange: (p, ps) => {
|
||||
onPageChange(p, ps)
|
||||
},
|
||||
|
||||
@@ -13,6 +13,7 @@ export interface TokenColumnHandlers {
|
||||
onCopyVoucher: (record: RockTokenItem) => void
|
||||
onPreviewVoucher: (record: RockTokenItem) => void
|
||||
onEditUid: (state: UidEditState) => void
|
||||
onViewRawData: (record: RockTokenItem) => void
|
||||
onResetToken: (id: number) => void
|
||||
onReleaseToken: (id: number) => void
|
||||
onUpdateRemark: (id: number, remark: string, status?: string) => void
|
||||
@@ -24,6 +25,7 @@ export function buildTokenColumns({
|
||||
onCopyVoucher,
|
||||
onPreviewVoucher,
|
||||
onEditUid,
|
||||
onViewRawData,
|
||||
onResetToken,
|
||||
onReleaseToken,
|
||||
onUpdateRemark,
|
||||
@@ -31,7 +33,7 @@ export function buildTokenColumns({
|
||||
}: TokenColumnHandlers): ColumnsType<RockTokenItem> {
|
||||
return [
|
||||
{
|
||||
title: '0666 编号 / 提取码',
|
||||
title: '0666 编号 / 兑换码',
|
||||
dataIndex: 'upstream_token_id',
|
||||
width: 250,
|
||||
render: (_, record) => (
|
||||
@@ -53,6 +55,32 @@ export function buildTokenColumns({
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '包ID / 提取码',
|
||||
width: 230,
|
||||
render: (_, record) => (
|
||||
<Space direction="vertical" size={2}>
|
||||
<div style={{ fontSize: 12, color: '#334155' }}>
|
||||
<span style={{ color: '#94a3b8' }}>包ID: </span>
|
||||
{record.package_id ? `#${record.package_id}` : '-'}
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<span style={{ color: '#94a3b8', fontSize: 12 }}>提取码:</span>
|
||||
<Text
|
||||
copyable={record.token ? { text: record.token } : false}
|
||||
style={{ fontSize: 12, fontFamily: 'monospace', fontWeight: 600 }}
|
||||
>
|
||||
{record.token || '-'}
|
||||
</Text>
|
||||
</div>
|
||||
{record.source === 'package' ? (
|
||||
<Tag color="purple" style={{ margin: 0, width: 'fit-content', fontSize: 10 }}>
|
||||
打包导入
|
||||
</Tag>
|
||||
) : null}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '规格与适用范围',
|
||||
dataIndex: 'color',
|
||||
@@ -338,6 +366,18 @@ export function buildTokenColumns({
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '原始数据',
|
||||
width: 100,
|
||||
render: (_, record) =>
|
||||
record.raw_data ? (
|
||||
<Button size="small" onClick={() => onViewRawData(record)}>
|
||||
查看
|
||||
</Button>
|
||||
) : (
|
||||
<Text type="secondary">-</Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
|
||||
Reference in New Issue
Block a user