增加异步日志和库存展示

This commit is contained in:
yml2213
2026-07-07 08:04:54 +08:00
parent 327b996079
commit 72d59670d4
7 changed files with 313 additions and 20 deletions
+94 -11
View File
@@ -107,6 +107,7 @@ type PrizeInfo = {
left_num?: number
status?: number
percent?: string
is_show_num?: number
img?: string
}
@@ -208,9 +209,77 @@ function priceOf(row?: PrizeInfo): number {
return row.new_score || row.score || 0
}
function leftOf(row?: PrizeInfo): number {
if (!row) return 0
return row.left_num || 0
type InventoryInfo = {
left?: number
total?: number
percent?: string
estimated: boolean
}
function inventoryOf(row?: PrizeInfo): InventoryInfo {
if (!row) return { estimated: false }
const total = Number(row.num || 0)
const percent = normalizePercent(row.percent)
const rawLeft = Number(row.left_num || 0)
if (rawLeft > 0 || percent === '0%') {
return {
left: rawLeft,
total: total > 0 ? total : undefined,
percent,
estimated: false,
}
}
if (total > 0 && percent) {
const percentValue = Number(percent.replace('%', ''))
if (Number.isFinite(percentValue)) {
return {
left: Math.floor((total * percentValue) / 100),
total,
percent,
estimated: true,
}
}
}
return {
total: total > 0 ? total : undefined,
percent,
estimated: false,
}
}
function normalizePercent(value?: string): string | undefined {
const text = String(value || '').trim()
if (!text) return undefined
const numeric = Number(text.replace('%', ''))
if (!Number.isFinite(numeric)) return text
return `${numeric}%`
}
function inventoryText(row?: PrizeInfo): string {
const info = inventoryOf(row)
const left = info.left === undefined ? '-' : `${info.estimated ? '约 ' : ''}${info.left}`
const total = info.total === undefined ? '-' : String(info.total)
return `剩余 ${left} / 总量 ${total}${info.percent ? ` · ${info.percent}` : ''}`
}
function summarizeInventory(items: PrizeInfo[]): string {
let left = 0
let total = 0
let leftKnown = 0
let totalKnown = 0
items.forEach((item) => {
const info = inventoryOf(item)
if (info.left !== undefined) {
left += info.left
leftKnown += 1
}
if (info.total !== undefined) {
total += info.total
totalKnown += 1
}
})
if (leftKnown === 0 && totalKnown === 0) return '库存未公开'
return `剩余 ${leftKnown ? left : '-'} / 总量 ${totalKnown ? total : '-'}`
}
function statusTag(status?: number, error?: string): ReactNode {
@@ -550,6 +619,7 @@ export default function Dashboard() {
String(priceOf(item)).includes(keyword),
)
}, [prizes, productSearch])
const inventorySummary = useMemo(() => summarizeInventory(filteredPrizes), [filteredPrizes])
const config = () => ({
...pickConfig(form.getFieldsValue(true)),
@@ -911,10 +981,9 @@ export default function Dashboard() {
const prizeColumns: ColumnsType<PrizeInfo> = useMemo(
() => [
{ title: 'num', dataIndex: 'id', width: 92 },
{ title: 'name', dataIndex: 'name', minWidth: 220, ellipsis: true },
{ title: '剩余', width: 84, render: (_, row) => leftOf(row) || '-' },
{ title: '总量', dataIndex: 'num', width: 84 },
{ title: 'PID', dataIndex: 'id', width: 92 },
{ title: '名称', dataIndex: 'name', minWidth: 220, ellipsis: true },
{ title: '库存', minWidth: 190, render: (_, row) => inventoryText(row) },
{ title: '价格', width: 84, render: (_, row) => priceOf(row) || '-' },
],
[],
@@ -1065,6 +1134,7 @@ export default function Dashboard() {
<div className="inventory-line">
<span>商品缓存 {filteredPrizes.length} 个</span>
<span>{inventorySummary}</span>
<span>{productListUpdatedAt ? `更新 ${productListUpdatedAt}` : '未缓存'}</span>
</div>
@@ -1091,9 +1161,9 @@ export default function Dashboard() {
</div>
<div className="product-meta">
<strong>{item.name}</strong>
<div>
<div className="product-tags">
<Tag color="gold">{priceOf(item)} 积分</Tag>
<Tag color="green">库存 {leftOf(item) || '-'}</Tag>
<InventoryTags prize={item} compact />
</div>
</div>
</button>
@@ -1425,18 +1495,31 @@ export default function Dashboard() {
)
}
function InventoryTags({ prize, compact = false }: { prize?: PrizeInfo; compact?: boolean }) {
const info = inventoryOf(prize)
const left = info.left === undefined ? '-' : `${info.estimated ? '约 ' : ''}${info.left}`
const total = info.total === undefined ? '-' : String(info.total)
return (
<span className={`inventory-tags${compact ? ' compact' : ''}`}>
<Tag color={info.left === 0 ? 'red' : 'green'}>剩余 {left}</Tag>
<Tag>总量 {total}</Tag>
{info.percent ? <Tag color="blue">{info.percent}</Tag> : null}
</span>
)
}
function CurrentProduct({ prize }: { prize?: PrizeInfo }) {
const name = prize?.name || '未从 CK 列表选择'
return (
<div className="current-product">
<span>当前商品</span>
<strong>{name}</strong>
<div>
<div className="current-product-tags">
{prize ? (
<>
<Tag color="gold">{priceOf(prize)} 积分</Tag>
<Tag color="green">库存 {leftOf(prize) || '-'}</Tag>
<Tag>PID {prize.id}</Tag>
<InventoryTags prize={prize} />
</>
) : (
<Tag>CK 商品源</Tag>
+24
View File
@@ -73,8 +73,32 @@ body {
font-size: 16px;
}
.current-product-tags,
.product-tags,
.inventory-tags {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px;
}
.inventory-tags {
display: inline-flex;
}
.inventory-tags.compact {
gap: 4px;
}
.inventory-tags .ant-tag,
.product-tags .ant-tag,
.current-product-tags .ant-tag {
margin-inline-end: 0;
}
.inventory-line {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 8px;