重构前端:迁移商品展示辅助方法

This commit is contained in:
yml
2026-05-25 01:27:56 +08:00
parent 3cf236def6
commit c5f99608d8
5 changed files with 4 additions and 4 deletions
+230
View File
@@ -0,0 +1,230 @@
import type { Listing } from "@/api/listings";
export interface ListingDisplayChip {
label: string;
value: string;
}
export interface ListingDisplayResource {
key: string;
label: string;
quantity: number;
mode: string;
}
export function getCoinWan(item: Listing) {
return Math.round(Number(item.haf_coin_amount || 0) / 10000);
}
export function getCoinM(item: Listing) {
return getCoinWan(item) / 100;
}
export function formatHafCoinM(amountWan: number) {
const amountM = amountWan / 100;
const rounded = Math.round(amountM * 10) / 10;
return `${Number.isInteger(rounded) ? rounded : rounded.toFixed(1)}M`;
}
export function getListingDisplayPrice(item: Listing) {
return Number(item.price || 0);
}
export function getRatioValue(item: Listing) {
const ratio = readAssetNumber(item, "publish_ratio");
if (ratio > 0) return ratio;
const price = getListingDisplayPrice(item);
if (price <= 0) return 0;
return getCoinWan(item) / price;
}
export function formatRatio(item: Listing) {
const ratio = getRatioValue(item);
return ratio > 0 ? `1:${formatRatioNumber(ratio)}` : "--";
}
export function getValuePerYuanText(item: Listing) {
return formatRatio(item);
}
export function getLoginMethod(item: Listing) {
return item.login_platform.trim();
}
export function getServerRegion(item: Listing) {
return item.server_region.trim();
}
export function getListingTitle(item: Listing) {
const parts = [
`纯币${formatHafCoinM(getCoinWan(item))}`,
formatInsuranceSlotText(readAssetString(item, "season_insurance")),
formatLevelShort(readAssetString(item, "stamina_level"), "体"),
formatLevelShort(readAssetString(item, "load_level"), "负"),
formatResourceShort(item, "armor6", "六甲"),
formatResourceShort(item, "helmet6", "六头"),
...getSkinNames(item).slice(0, 4),
].filter(Boolean);
return parts.join("/");
}
export function getListingSubtitle(item: Listing) {
return getValuePerYuanText(item);
}
export function getListingChips(item: Listing): ListingDisplayChip[] {
const totalAsset = readAssetNumber(item, "total_asset_wan");
const chips: ListingDisplayChip[] = [
{ label: "哈夫币", value: formatHafCoinM(getCoinWan(item)) },
{ label: "保险格数", value: readAssetString(item, "season_insurance") },
{ label: "体力", value: readAssetString(item, "stamina_level") },
{ label: "负重", value: readAssetString(item, "load_level") },
{ label: "段位", value: item.rank_level },
];
const awmAmmo = getResourceQuantity(item, "awmAmmo");
if (awmAmmo > 0) {
chips.push({ label: "AWM", value: `${awmAmmo}` });
}
if (totalAsset > 0) {
chips.push({ label: "总资产", value: formatHafCoinM(totalAsset) });
}
const online = getOnlineTimeText(item);
if (online) {
chips.push({ label: "方便上号", value: online });
}
return chips.filter((chip) => chip.value);
}
export function getListingResources(item: Listing): ListingDisplayResource[] {
const resources = item.asset_summary?.resources;
if (!Array.isArray(resources)) return [];
return resources
.map((resource) => {
if (typeof resource !== "object" || resource === null) return null;
const row = resource as Record<string, unknown>;
return {
key: typeof row.key === "string" ? row.key : "",
label: typeof row.label === "string" ? row.label : "",
quantity: readUnknownNumber(row.quantity),
mode: typeof row.mode === "string" ? row.mode : "",
};
})
.filter((resource): resource is ListingDisplayResource => {
return Boolean(resource?.key && resource.label && resource.quantity > 0);
});
}
export function getResourceQuantity(item: Listing, resourceKey: string) {
return getListingResources(item).find((resource) => resource.key === resourceKey)?.quantity || 0;
}
export function hasGiftResources(item: Listing) {
return getListingResources(item).some((resource) => resource.mode === "赠送");
}
export function hasAcceleratedSaleRatio(item: Listing) {
if (item.is_accelerated_sale) return true;
const priceBreakdown = item.asset_summary?.price_breakdown;
if (typeof priceBreakdown !== "object" || priceBreakdown === null) return false;
const row = priceBreakdown as Record<string, unknown>;
const referenceRatio = readUnknownNumber(row.seller_reference_ratio);
const sellerRatio = readUnknownNumber(row.seller_ratio);
const acceleratedRatio = readUnknownNumber(row.accelerated_sale_ratio);
if (referenceRatio <= 0) return false;
return sellerRatio > referenceRatio || acceleratedRatio > referenceRatio;
}
export function getSkinGroup(item: Listing, groupKey: string) {
const skinGroups = item.asset_summary?.skin_groups;
if (
typeof skinGroups !== "object" ||
skinGroups === null ||
!Array.isArray((skinGroups as Record<string, unknown>)[groupKey])
) {
return [];
}
return ((skinGroups as Record<string, unknown>)[groupKey] as unknown[]).filter(
(skin): skin is string => typeof skin === "string"
);
}
export function getSkinNames(item: Listing) {
const skinGroups = item.asset_summary?.skin_groups;
if (typeof skinGroups !== "object" || skinGroups === null) return [];
return Object.values(skinGroups as Record<string, unknown>)
.flatMap((group) => (Array.isArray(group) ? group : []))
.filter((skin): skin is string => typeof skin === "string");
}
export function assetRegions(item: Listing) {
const regions = item.asset_summary?.common_regions;
return Array.isArray(regions)
? regions.filter((region): region is string => typeof region === "string")
: [];
}
export function getOnlineTimeText(item: Listing) {
const onlineTime = item.asset_summary?.online_time;
if (typeof onlineTime !== "object" || onlineTime === null) return "";
const start = (onlineTime as Record<string, unknown>).start;
const end = (onlineTime as Record<string, unknown>).end;
if (typeof start !== "string" || typeof end !== "string" || !start || !end) return "";
return `${start.replace(":00", "")}-${end.replace(":00", "")}`;
}
export function getDailyLoss(item: Listing) {
const coinWan = getCoinWan(item);
if (coinWan >= 30000) return "30M";
if (coinWan >= 10000) return "20M";
return "10M";
}
export function readAssetString(item: Listing, key: string) {
const value = item.asset_summary?.[key];
return typeof value === "string" ? value : "";
}
export function readAssetNumber(item: Listing, key: string) {
return readUnknownNumber(item.asset_summary?.[key]);
}
function readUnknownNumber(value: unknown) {
if (typeof value === "number") return value;
if (typeof value === "string" && value.trim()) {
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : 0;
}
return 0;
}
function formatInsuranceSlotText(value: string) {
const parts = value.split("*").map((item) => Number(item));
const rows = parts[0] || 0;
const cols = parts[1] || 0;
if (!Number.isFinite(rows) || !Number.isFinite(cols) || rows <= 0 || cols <= 0) {
return value;
}
return `${rows * cols}`;
}
function formatLevelShort(value: string, suffix: string) {
const level = value.match(/\d+/)?.[0];
return level ? `${level}${suffix}` : value;
}
function formatResourceShort(item: Listing, key: string, label: string) {
const quantity = getResourceQuantity(item, key);
return quantity > 0 ? `${quantity}${label}` : "";
}
function roundMoney(value: number) {
return Math.round(value * 100) / 100;
}
function formatRatioNumber(value: number) {
const rounded = roundMoney(value);
return Number.isInteger(rounded) ? `${rounded}` : rounded.toFixed(2);
}