优化首页展示列表
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
import {
|
||||
defaultListingPublishOptions,
|
||||
type ListingPublishOptions,
|
||||
} from "@/api/listingOptions";
|
||||
import type { Listing } from "@/api/listings";
|
||||
|
||||
const fallbackRegionOptions = ["广东", "上海", "江苏", "四川", "北京", "浙江"];
|
||||
|
||||
const coinWanOptions = [
|
||||
1800, 3200, 5800, 9600, 12000, 18000, 26000, 36000, 52000, 68000,
|
||||
];
|
||||
const depositOptions = [60, 80, 100, 120, 160, 200];
|
||||
const secretKdOptions = [1.2, 1.6, 2.1, 2.8, 3.4, 4.2];
|
||||
const onlineWindows = [
|
||||
["09:00", "23:30"],
|
||||
["10:30", "01:00"],
|
||||
["12:00", "24:00"],
|
||||
["18:00", "02:00"],
|
||||
] as const;
|
||||
const resourceQuantityPresets: Record<string, number[]> = {
|
||||
awmAmmo: [0, 20, 48, 80, 120, 180],
|
||||
helmet6: [0, 2, 4, 6, 10, 16],
|
||||
armor6: [0, 1, 3, 5, 8, 12],
|
||||
kit5: [0, 3, 6, 10, 15, 24],
|
||||
level6Ammo: [0, 120, 240, 360, 520, 800],
|
||||
gridCard9: [0, 1, 2, 4, 6, 10],
|
||||
};
|
||||
|
||||
function pick<T>(items: readonly T[], index: number, fallback: T): T {
|
||||
if (!items.length) return fallback;
|
||||
return items[index % items.length] ?? fallback;
|
||||
}
|
||||
|
||||
function pickMany(items: string[], start: number, count: number) {
|
||||
if (!items.length) return [];
|
||||
const fallback = items[0] || "";
|
||||
return Array.from({ length: Math.min(count, items.length) }, (_, idx) =>
|
||||
pick(items, start + idx, fallback)
|
||||
).filter(Boolean);
|
||||
}
|
||||
|
||||
function buildResources(options: ListingPublishOptions, seed: number) {
|
||||
return options.quantity_items.map((item, index) => ({
|
||||
key: item.key,
|
||||
label: item.label,
|
||||
quantity: pick(
|
||||
resourceQuantityPresets[item.key] || [0, 1, 3, 6],
|
||||
seed + index,
|
||||
0
|
||||
),
|
||||
mode: "收费",
|
||||
}));
|
||||
}
|
||||
|
||||
function buildSkinGroups(options: ListingPublishOptions, seed: number) {
|
||||
return options.skin_groups.reduce<Record<string, string[]>>((groups, group, index) => {
|
||||
const count = group.key === "melee" ? 2 : index % 2 === 0 ? 3 : 2;
|
||||
groups[group.key] = pickMany(group.options, seed + index * 2, count);
|
||||
return groups;
|
||||
}, {});
|
||||
}
|
||||
|
||||
function buildScreenshotMap(options: ListingPublishOptions, seed: number) {
|
||||
return options.screenshot_slots.reduce<Record<string, string>>((screenshots, slot, index) => {
|
||||
screenshots[slot.key] = `https://picsum.photos/seed/hfb-${slot.key}-${seed + index}/960/540`;
|
||||
return screenshots;
|
||||
}, {});
|
||||
}
|
||||
|
||||
function flattenSkinGroups(groups: Record<string, string[]>) {
|
||||
return Object.values(groups).flat();
|
||||
}
|
||||
|
||||
function calculateRentDays(coinWan: number) {
|
||||
return coinWan >= 30000 ? 7 : coinWan >= 10000 ? 3 : 1;
|
||||
}
|
||||
|
||||
function calculateDailyLoss(coinWan: number) {
|
||||
return coinWan >= 30000 ? "30M" : coinWan >= 10000 ? "20M" : "10M";
|
||||
}
|
||||
|
||||
function roundMoney(value: number) {
|
||||
return Math.round(value * 100) / 100;
|
||||
}
|
||||
|
||||
function formatHafCoinM(coinWan: number) {
|
||||
const coinM = Math.round((coinWan / 100) * 10) / 10;
|
||||
return `${Number.isInteger(coinM) ? coinM : coinM.toFixed(1)}M`;
|
||||
}
|
||||
|
||||
export function buildFallbackListings(
|
||||
options: ListingPublishOptions = defaultListingPublishOptions
|
||||
): Listing[] {
|
||||
return Array.from({ length: 10 }, (_, index) => {
|
||||
const seed = index + 1;
|
||||
const server = pick(options.server_options, index, "QQ");
|
||||
const loginMethod = pick(options.login_method_options, index + 1, "账号密码");
|
||||
const rank = pick(options.rank_options, index + 3, "钻石");
|
||||
const insurance = pick(options.insurance_options, index + 1, "2*2");
|
||||
const stamina = pick(options.level_options, index + 4, "5级");
|
||||
const load = pick(options.level_options, index + 5, "5级");
|
||||
const faceOwner = pick(options.face_options, index, "是");
|
||||
const coinWan = pick(coinWanOptions, index, 12000);
|
||||
const ratio = 5 + (index % 4);
|
||||
const rentDays = calculateRentDays(coinWan);
|
||||
const finalPrice = roundMoney(coinWan / ratio);
|
||||
const settlementAmount = finalPrice;
|
||||
const dailyPrice = roundMoney(finalPrice / rentDays);
|
||||
const hourlyPrice = Math.max(roundMoney(dailyPrice / 24), 0.01);
|
||||
const deposit = pick(depositOptions, index, 100);
|
||||
const skinGroups = buildSkinGroups(options, seed);
|
||||
const screenshots = buildScreenshotMap(options, seed);
|
||||
const commonRegions = pickMany(
|
||||
options.region_options.length ? options.region_options : fallbackRegionOptions,
|
||||
index * 2,
|
||||
2
|
||||
);
|
||||
const [onlineStart, onlineEnd] = pick(onlineWindows, index, onlineWindows[0]);
|
||||
|
||||
return {
|
||||
id: 9100 + seed,
|
||||
account_id: 0,
|
||||
owner_id: 0,
|
||||
title: `${server} ${rank} ${formatHafCoinM(coinWan)}哈夫币`,
|
||||
description: `${loginMethod}交接,${insurance}保险,体力${stamina}、负重${load},示例数据按发布表单随机生成。`,
|
||||
game_name: "三角洲行动",
|
||||
server_region: server,
|
||||
login_platform: loginMethod,
|
||||
rank_level: rank,
|
||||
haf_coin_amount: coinWan * 10000,
|
||||
asset_summary: {
|
||||
face_owner: faceOwner,
|
||||
haf_coin_wan: coinWan,
|
||||
total_asset_wan: Math.round(coinWan * (1.08 + (index % 4) * 0.04)),
|
||||
secret_kd: pick(secretKdOptions, index, 1.6),
|
||||
fire_level: 38 + seed * 3,
|
||||
season_insurance: insurance,
|
||||
stamina_level: stamina,
|
||||
load_level: load,
|
||||
daily_loss: calculateDailyLoss(coinWan),
|
||||
ratio,
|
||||
login_method: loginMethod,
|
||||
common_regions: commonRegions,
|
||||
resources: buildResources(options, seed),
|
||||
skins: flattenSkinGroups(skinGroups),
|
||||
skin_groups: skinGroups,
|
||||
online_time: {
|
||||
start: onlineStart,
|
||||
end: onlineEnd,
|
||||
},
|
||||
ban_record: index % 4 === 0 ? "无封禁记录,近期登录稳定" : "",
|
||||
screenshots,
|
||||
deposit_amount: deposit,
|
||||
price: finalPrice,
|
||||
settlement_amount: settlementAmount,
|
||||
rent_days: rentDays,
|
||||
remark:
|
||||
index % 3 === 0
|
||||
? "部分仓库材料请勿使用,下单后会在群聊再次提醒。"
|
||||
: "",
|
||||
},
|
||||
screenshot_urls: Object.values(screenshots),
|
||||
price_hourly: hourlyPrice,
|
||||
price_daily: dailyPrice,
|
||||
price_weekly: Math.round(dailyPrice * 7 * 10) / 10,
|
||||
deposit_amount: deposit,
|
||||
min_rent_hours: coinWan >= 10000 ? 24 : 8,
|
||||
max_rent_hours: coinWan >= 30000 ? 168 : 72,
|
||||
status: "published",
|
||||
review_status: "approved",
|
||||
review_reason: "",
|
||||
published_at: new Date(Date.now() - seed * 18 * 60 * 1000).toISOString(),
|
||||
created_at: new Date(Date.now() - seed * 20 * 60 * 1000).toISOString(),
|
||||
updated_at: new Date(Date.now() - seed * 10 * 60 * 1000).toISOString(),
|
||||
};
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user