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 = { 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(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>((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>((screenshots, slot, index) => { screenshots[slot.key] = `https://picsum.photos/seed/hfb-${slot.key}-${seed + index}/960/540`; return screenshots; }, {}); } function flattenSkinGroups(groups: Record) { 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(), }; }); }