Files
wzdj/lib/db/mongo/seed-mongo.ts
2026-04-11 17:15:11 +08:00

294 lines
22 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 玩值电竞 - MongoDB 建库 + 索引 + 种子数据
* 执行pnpm db:mongo:seed会读取项目根目录 .env.local 中的 MONGODB_URI
*/
import { config } from "dotenv"
import { resolve } from "path"
config({ path: resolve(process.cwd(), ".env.local") })
import { ObjectId } from "mongodb"
import { getDb, closeMongo } from "../../mongodb/client"
import { COLLECTIONS, INDEX_SPECS } from "./collections"
import { ensureCollections } from "./ensure-indexes"
import { LYTIAO_STREAMERS, LYTIAO_SOURCE } from "../../data/lytiao-streamers"
import { hashPassword } from "../../auth-utils"
const now = () => new Date().toISOString()
async function ensureIndexes() {
const db = await getDb()
for (const [name, specs] of Object.entries(INDEX_SPECS)) {
const coll = db.collection(name)
if (specs.length > 0) {
try {
await coll.createIndexes(specs)
} catch (e: unknown) {
const err = e as { code?: number }
if (err.code !== 85 && err.code !== 86) throw e
}
}
}
}
async function seed() {
const db = await getDb()
const gamesColl = db.collection(COLLECTIONS.games)
const usersColl = db.collection(COLLECTIONS.users)
const streamersColl = db.collection(COLLECTIONS.streamers)
// 1. 游戏(仅当无数据时写入)
const gamesCount = await gamesColl.countDocuments()
if (gamesCount === 0) {
const games = [
{ name: "王者荣耀", shortName: "wzry", logo: "/wzry.jpg", coverImage: "/wzry-cover.jpg", category: "moba", platform: ["mobile"], publisher: "腾讯", isHot: true, sortOrder: 1, status: "active", createdAt: now() },
{ name: "英雄联盟", shortName: "lol", logo: "/lol.jpg", coverImage: "/lol-cover.jpg", category: "moba", platform: ["pc"], publisher: "腾讯", isHot: true, sortOrder: 2, status: "active", createdAt: now() },
{ name: "和平精英", shortName: "pubgm", logo: "/pubgm.jpg", coverImage: "/pubgm-cover.jpg", category: "fps", platform: ["mobile"], publisher: "腾讯", isHot: true, sortOrder: 3, status: "active", createdAt: now() },
{ name: "原神", shortName: "ys", logo: "/ys.jpg", coverImage: "/ys-cover.jpg", category: "mmorpg", platform: ["pc", "mobile"], publisher: "米哈游", isHot: true, sortOrder: 4, status: "active", createdAt: now() },
{ name: "无畏契约", shortName: "valorant", logo: "/valorant.jpg", coverImage: "/valorant-cover.jpg", category: "fps", platform: ["pc"], publisher: "拳头", isHot: true, sortOrder: 5, status: "active", createdAt: now() },
{ name: "穿越火线", shortName: "cf", logo: "/cf.jpg", coverImage: "/cf-cover.jpg", category: "fps", platform: ["pc", "mobile"], publisher: "腾讯", isHot: false, sortOrder: 6, status: "active", createdAt: now() },
{ name: "梦幻西游", shortName: "mhxy", logo: "/mhxy.jpg", coverImage: "/mhxy-cover.jpg", category: "mmorpg", platform: ["pc", "mobile"], publisher: "网易", isHot: false, sortOrder: 7, status: "active", createdAt: now() },
{ name: "三角洲行动", shortName: "delta", logo: "/delta.jpg", coverImage: "/delta-cover.jpg", category: "fps", platform: ["pc", "mobile"], publisher: "腾讯", isHot: true, sortOrder: 8, status: "active", createdAt: now() },
{ name: "魔兽世界", shortName: "wow", logo: "/wow.jpg", coverImage: "/wow-cover.jpg", category: "mmorpg", platform: ["pc"], publisher: "暴雪", isHot: false, sortOrder: 9, status: "active", createdAt: now() },
]
await gamesColl.insertMany(games)
console.log("[Mongo] games:", games.length)
} else {
console.log("[Mongo] games 已有数据,跳过")
}
// 2. 用户(仅当无用户时写入默认用户)
const usersCount = await usersColl.countDocuments()
let userId: import("mongodb").ObjectId
if (usersCount === 0) {
const defaultUser = {
odlId: "888888",
phone: "13800138000",
name: "卡若",
avatar: "/gamer-boy-esports-jersey.jpg",
level: 12,
experience: 2450,
isVip: false,
gender: "male",
tags: ["英雄联盟", "王者荣耀"],
activity: 128,
following: 45,
followers: 892,
visitors: 1205,
balance: 6880,
totalRecharge: 10000,
totalSpent: 3120,
registerSource: "app",
registerTime: "2023-01-15",
lastLoginTime: now(),
status: "active",
createdAt: "2023-01-15",
updatedAt: now(),
}
const userRes = await usersColl.insertOne(defaultUser)
userId = userRes.insertedId
console.log("[Mongo] users: 1 (default)")
} else {
const first = await usersColl.findOne({})
if (!first || !(first as { _id?: unknown })._id) throw new Error("users 集合为空,请先执行全量种子")
userId = (first as { _id: import("mongodb").ObjectId })._id
console.log("[Mongo] users 已有数据,跳过")
}
// 2b. 管理端账号 admin / k123456仅当无管理员时写入
const adminsColl = db.collection(COLLECTIONS.admins)
const adminsCount = await adminsColl.countDocuments()
if (adminsCount === 0) {
await adminsColl.insertOne({
username: "admin",
passwordHash: hashPassword("k123456"),
createdAt: new Date(),
updatedAt: new Date(),
})
console.log("[Mongo] admins: 1 (admin)")
}
// 2c. 前端测试账号 15880802661 卡若 k123456仅当该手机号未注册时写入
const authsColl = db.collection(COLLECTIONS.userAuths)
const hasKaruo = await authsColl.findOne({ authType: "phone", authId: "15880802661" })
if (!hasKaruo) {
const karuoId = new ObjectId()
await usersColl.insertOne({
_id: karuoId,
name: "卡若",
phone: "15880802661",
avatar: "",
level: 1,
balance: 0,
status: "active",
createdAt: new Date(),
updatedAt: new Date(),
})
await authsColl.insertOne({
userId: karuoId,
authType: "phone",
authId: "15880802661",
credential: hashPassword("k123456"),
createdAt: new Date(),
updatedAt: new Date(),
})
console.log("[Mongo] 测试用户: 15880802661 卡若")
}
// 3. 主播:默认 6 条(仅当无主播时写入);老游条导师(按 source+name 去重补充)
const streamersCount = await streamersColl.countDocuments()
if (streamersCount === 0) {
const streamers = [
{ userId: userId.toString(), name: "GM-远洋", avatar: "/streamer-1.jpg", coverImage: "/lol-stream.jpg", title: "国服第一盲僧", game: "英雄联盟", gameId: 2, tags: ["打野", "教学"], level: 28, fans: 1256000, hotValue: 125.6, isLive: true, totalGifts: 89000, totalIncome: 156000, commissionRate: 0.7, status: "approved", verifiedAt: "2023-02-01", createdAt: "2023-01-20", updatedAt: now() },
{ userId: userId.toString(), name: "小狐狸", avatar: "/streamer-2.jpg", coverImage: "/valorant-stream.jpg", title: "无畏契约电竞女神", game: "无畏契约", gameId: 5, tags: ["竞技", "颜值"], level: 25, fans: 856000, hotValue: 89.2, isLive: true, totalGifts: 67000, totalIncome: 98000, commissionRate: 0.7, status: "approved", verifiedAt: "2023-03-01", createdAt: "2023-02-15", updatedAt: now() },
{ userId: userId.toString(), name: "王者阿杰", avatar: "/streamer-3.jpg", coverImage: "/wzry-stream.jpg", title: "国服最强边路", game: "王者荣耀", gameId: 1, tags: ["边路", "上分"], level: 30, fans: 2100000, hotValue: 168.5, isLive: false, totalGifts: 125000, totalIncome: 230000, commissionRate: 0.75, status: "approved", verifiedAt: "2023-01-10", createdAt: "2022-12-01", updatedAt: now() },
{ userId: userId.toString(), name: "原神小可爱", avatar: "/streamer-4.jpg", coverImage: "/ys-stream.jpg", title: "深渊满星攻略", game: "原神", gameId: 4, tags: ["攻略", "抽卡"], level: 22, fans: 568000, hotValue: 56.8, isLive: true, totalGifts: 45000, totalIncome: 78000, commissionRate: 0.65, status: "approved", verifiedAt: "2023-04-01", createdAt: "2023-03-10", updatedAt: now() },
{ userId: userId.toString(), name: "吃鸡大魔王", avatar: "/streamer-5.jpg", coverImage: "/pubgm-stream.jpg", title: "单排上分王", game: "和平精英", gameId: 3, tags: ["吃鸡", "技巧"], level: 26, fans: 980000, hotValue: 98.0, isLive: true, totalGifts: 72000, totalIncome: 135000, commissionRate: 0.7, status: "approved", verifiedAt: "2023-02-15", createdAt: "2023-01-25", updatedAt: now() },
{ userId: userId.toString(), name: "魔兽老玩家", avatar: "/streamer-6.jpg", coverImage: "/wow-stream.jpg", title: "怀旧服金团领队", game: "魔兽世界", gameId: 9, tags: ["怀旧", "金团"], level: 20, fans: 320000, hotValue: 32.5, isLive: false, totalGifts: 28000, totalIncome: 52000, commissionRate: 0.65, status: "approved", verifiedAt: "2023-05-01", createdAt: "2023-04-20", updatedAt: now() },
]
await streamersColl.insertMany(streamers)
console.log("[Mongo] streamers (默认):", streamers.length)
} else {
console.log("[Mongo] streamers 已有数据,仅补充老游条")
}
// 老游条导师:按 source+name 去重,不存在则插入
let lytiaoInserted = 0
for (const s of LYTIAO_STREAMERS) {
const exists = await streamersColl.findOne({ source: LYTIAO_SOURCE, name: s.name })
if (exists) continue
const fans = s.douyuFans ?? s.douyinFans ?? 0
const avatar = s.avatar || `/streamers/lytiao/${s.name.replace(/[\u3000]/g, "").trim()}.jpg`
await streamersColl.insertOne({
userId: userId.toString(),
name: s.name,
title: s.title,
intro: s.intro,
game: s.game,
gameId: s.gameId,
tags: s.tags,
avatar,
coverImage: s.coverImage || "",
level: 20,
fans: Math.max(0, fans),
douyuFans: s.douyuFans ?? undefined,
douyinFans: s.douyinFans ?? undefined,
hotValue: 0,
isLive: false,
totalGifts: 0,
totalIncome: 0,
commissionRate: 0.7,
status: "approved",
verifiedAt: now(),
source: LYTIAO_SOURCE,
city: s.city ?? "深圳",
createdAt: now(),
updatedAt: now(),
})
lytiaoInserted++
}
if (lytiaoInserted > 0) console.log("[Mongo] 老游条主播 新增:", lytiaoInserted)
// 以下仅在全量种子时写入(即 games 原本为空时)
if (gamesCount > 0) {
console.log("[Mongo] 其余种子(明星/公会等)已有数据,跳过")
return
}
// 4. 明星
const starsColl = db.collection(COLLECTIONS.stars)
const stars = [
{ userId: userId.toString(), name: "Faker", avatar: "/star-faker.jpg", coverImage: "/star-faker-cover.jpg", title: "LOL传奇中单", game: "英雄联盟", gameId: 2, tags: ["世界冠军", "中单"], fans: 46800000, hotValue: 468.0, achievements: ["三冠王", "S赛MVP"], teamName: "T1", socialLinks: { weibo: "faker_lol" }, partyRoomId: "faker-party", hourlyRate: 9999, isOnline: true, status: "active", verifiedAt: "2022-01-01", createdAt: "2022-01-01", updatedAt: now() },
{ userId: userId.toString(), name: "Uzi", avatar: "/star-uzi.jpg", coverImage: "/star-uzi-cover.jpg", title: "永远的神", game: "英雄联盟", gameId: 2, tags: ["ADC", "传奇"], fans: 38500000, hotValue: 385.0, achievements: ["MSI冠军", "LPL冠军"], teamName: "RNG", socialLinks: { weibo: "uzi_lol", douyin: "uzi" }, partyRoomId: "uzi-party", hourlyRate: 8888, isOnline: false, status: "active", verifiedAt: "2022-01-01", createdAt: "2022-01-01", updatedAt: now() },
{ userId: userId.toString(), name: "梦泪", avatar: "/star-menglei.jpg", coverImage: "/star-menglei-cover.jpg", title: "国服第一韩信", game: "王者荣耀", gameId: 1, tags: ["韩信", "打野"], fans: 52000000, hotValue: 520.0, achievements: ["KPL冠军", "最佳打野"], teamName: "AG超玩会", socialLinks: { douyin: "menglei" }, partyRoomId: "menglei-party", hourlyRate: 6666, isOnline: true, status: "active", verifiedAt: "2022-06-01", createdAt: "2022-06-01", updatedAt: now() },
{ userId: userId.toString(), name: "不求人", avatar: "/star-buqiuren.jpg", coverImage: "/star-buqiuren-cover.jpg", title: "和平精英一哥", game: "和平精英", gameId: 3, tags: ["吃鸡", "主播"], fans: 41000000, hotValue: 410.0, achievements: ["PEL冠军", "全明星MVP"], socialLinks: { douyin: "buqiuren" }, partyRoomId: "buqiuren-party", hourlyRate: 5888, isOnline: true, status: "active", verifiedAt: "2022-03-01", createdAt: "2022-03-01", updatedAt: now() },
]
await starsColl.insertMany(stars)
console.log("[Mongo] stars:", stars.length)
// 4.1 派对群(与明星关联,基础数据)
const firstStar = await starsColl.findOne({})
const firstStarId = firstStar ? (firstStar as { _id: import("mongodb").ObjectId })._id.toString() : ""
const partyRoomsColl = db.collection(COLLECTIONS.starPartyRooms)
const partyRoomsCount = await partyRoomsColl.countDocuments()
if (partyRoomsCount === 0 && firstStarId) {
const partyRooms = [
{ starId: firstStarId, name: "Faker 粉丝派对", coverImage: "/party-lol.jpg", memberCount: 12, maxMembers: 50, entryFee: 0, description: "与 Faker 一起开黑", rules: ["文明发言"], isActive: true, createdAt: now(), updatedAt: now() },
{ starId: firstStarId, name: "梦泪车队派对", coverImage: "/party-hok.jpg", memberCount: 8, maxMembers: 30, entryFee: 9, description: "带粉上分", rules: [], isActive: true, createdAt: now(), updatedAt: now() },
]
await partyRoomsColl.insertMany(partyRooms)
console.log("[Mongo] starPartyRooms:", partyRooms.length)
}
// 5. 公会(含玩值电竞、丸子公会)
const guildsColl = db.collection(COLLECTIONS.guilds)
const guilds = [
{ name: "玩值电竞", logo: "", coverImage: "", description: "玩值电竞官方公会", ownerId: userId.toString(), memberCount: 0, maxMembers: 5000, level: 10, totalIncome: 0, commissionRate: 0.1, tags: ["官方", "电竞"], games: ["魔兽世界", "英雄联盟", "王者荣耀"], requirements: "", benefits: ["流量扶持", "课程分成"], status: "active", createdAt: "2022-01-01", updatedAt: now() },
{ name: "丸子公会", logo: "", coverImage: "", description: "丸子公会,星探与主播培养", ownerId: userId.toString(), memberCount: 0, maxMembers: 5000, level: 10, totalIncome: 0, commissionRate: 0.1, tags: ["公会", "主播"], games: ["英雄联盟", "王者荣耀"], requirements: "", benefits: ["流量扶持"], status: "active", createdAt: "2022-06-01", updatedAt: now() },
{ name: "星耀电竞", logo: "/guild-xingyao.jpg", coverImage: "/guild-xingyao-cover.jpg", description: "顶级电竞公会", ownerId: userId.toString(), memberCount: 1280, maxMembers: 2000, level: 8, totalIncome: 2580000, commissionRate: 0.1, tags: ["职业", "培训"], games: ["英雄联盟", "王者荣耀"], requirements: "段位王者以上", benefits: ["签约底薪", "流量扶持"], status: "active", createdAt: "2022-01-01", updatedAt: now() },
{ name: "凤凰涅槃", logo: "/guild-fenghuang.jpg", coverImage: "/guild-fenghuang-cover.jpg", description: "女主播孵化基地", ownerId: userId.toString(), memberCount: 860, maxMembers: 1500, level: 6, totalIncome: 1680000, commissionRate: 0.12, tags: ["颜值", "才艺"], games: ["王者荣耀", "和平精英"], requirements: "颜值在线", benefits: ["形象包装", "运营指导"], status: "active", createdAt: "2022-06-01", updatedAt: now() },
{ name: "暗影战队", logo: "/guild-anying.jpg", coverImage: "/guild-anying-cover.jpg", description: "FPS游戏专业公会", ownerId: userId.toString(), memberCount: 520, maxMembers: 1000, level: 5, totalIncome: 980000, commissionRate: 0.1, tags: ["FPS", "硬核"], games: ["和平精英", "无畏契约"], requirements: "FPS高段位", benefits: ["战队训练", "比赛机会"], status: "active", createdAt: "2023-01-01", updatedAt: now() },
]
await guildsColl.insertMany(guilds)
console.log("[Mongo] guilds:", guilds.length)
// 6. CP/陪练
const companionsColl = db.collection(COLLECTIONS.companions)
const companions = [
{ userId: userId.toString(), name: "甜心小姐姐", avatar: "/cp-avatar-1.jpg", coverImage: "/cp-cover-1.jpg", gender: "female", age: 22, tags: ["甜美", "温柔"], games: ["王者荣耀", "和平精英"], bio: "声音甜美,陪你上分~", price: 30, originalPrice: 50, rating: 4.9, ordersCount: 1256, responseRate: 98, onlineStatus: "online", category: "cp", commissionRate: 0.3, status: "active", createdAt: "2023-01-01", updatedAt: now() },
{ userId: userId.toString(), name: "电竞小王子", avatar: "/cp-avatar-2.jpg", coverImage: "/cp-cover-2.jpg", gender: "male", age: 24, tags: ["阳光", "幽默"], games: ["英雄联盟", "无畏契约"], bio: "王者段位,带你上分", price: 35, originalPrice: 60, rating: 4.8, ordersCount: 986, responseRate: 95, onlineStatus: "online", category: "cp", commissionRate: 0.3, status: "active", createdAt: "2023-02-01", updatedAt: now() },
{ userId: userId.toString(), name: "职业选手小明", avatar: "/coach-avatar-1.jpg", coverImage: "/coach-cover-1.jpg", gender: "male", age: 26, tags: ["职业", "教学"], games: ["英雄联盟"], voiceSample: "/voice-sample-1.mp3", bio: "前职业选手,专业教学", price: 100, originalPrice: 150, rating: 4.95, ordersCount: 568, responseRate: 99, onlineStatus: "online", category: "coach", coachType: "pro", rank: "王者", commissionRate: 0.25, status: "active", createdAt: "2023-01-15", updatedAt: now() },
{ userId: userId.toString(), name: "王者大神", avatar: "/coach-avatar-2.jpg", coverImage: "/coach-cover-2.jpg", gender: "male", age: 23, tags: ["上分", "技术流"], games: ["王者荣耀"], bio: "国服百星", price: 80, originalPrice: 120, rating: 4.88, ordersCount: 892, responseRate: 97, onlineStatus: "busy", category: "coach", coachType: "master", rank: "荣耀王者100星", commissionRate: 0.25, status: "active", createdAt: "2023-03-01", updatedAt: now() },
]
await companionsColl.insertMany(companions)
console.log("[Mongo] companions:", companions.length)
// 7. 电竞酒店/网咖
const venuesColl = db.collection(COLLECTIONS.esportsVenues)
const venues = [
{ name: "玩值电竞酒店(旗舰店)", type: "hotel", logo: "/hotel-logo-1.jpg", images: ["/hotel-1.jpg"], description: "五星级电竞酒店", address: "厦门市思明区软件园二期", city: "厦门", district: "思明区", latitude: 24.4798, longitude: 118.0894, phone: "0592-12345678", rating: 4.9, reviewCount: 1256, pricePerNight: 399, facilities: ["RTX4090", "电竞椅", "144Hz显示器"], tags: ["热门", "高端"], openTime: "00:00", closeTime: "24:00", isOpen24Hours: true, status: "active", createdAt: "2022-01-01", updatedAt: now() },
{ name: "极客空间电竞公寓", type: "hotel", logo: "/hotel-logo-2.jpg", images: ["/hotel-2.jpg"], description: "年轻人的电竞乐园", address: "厦门市湖里区五缘湾", city: "厦门", district: "湖里区", latitude: 24.5102, longitude: 118.1456, phone: "0592-23456789", rating: 4.7, reviewCount: 896, pricePerNight: 299, facilities: ["RTX3080", "电竞椅"], tags: ["性价比"], openTime: "00:00", closeTime: "24:00", isOpen24Hours: true, status: "active", createdAt: "2022-06-01", updatedAt: now() },
{ name: "网鱼网咖(万达店)", type: "cafe", logo: "/cafe-logo-1.jpg", images: ["/cafe-1.jpg"], description: "专业电竞网咖", address: "厦门市思明区万达广场", city: "厦门", district: "思明区", latitude: 24.4656, longitude: 118.1023, phone: "0592-34567890", rating: 4.8, reviewCount: 2356, pricePerHour: 12, facilities: ["3080显卡", "特权公馆"], tags: ["连锁", "环境好"], openTime: "00:00", closeTime: "24:00", isOpen24Hours: true, status: "active", createdAt: "2021-01-01", updatedAt: now() },
{ name: "杰拉电竞馆", type: "cafe", logo: "/cafe-logo-2.jpg", images: ["/cafe-2.jpg"], description: "赛事级电竞馆", address: "厦门市集美区银泰城", city: "厦门", district: "集美区", latitude: 24.5789, longitude: 118.0956, phone: "0592-45678901", rating: 4.6, reviewCount: 1568, pricePerHour: 10, facilities: ["赛事级配置", "独立包间"], tags: ["比赛场地"], openTime: "09:00", closeTime: "02:00", isOpen24Hours: false, status: "active", createdAt: "2022-03-01", updatedAt: now() },
]
await venuesColl.insertMany(venues)
console.log("[Mongo] esportsVenues:", venues.length)
// 8. 商品
const productsColl = db.collection(COLLECTIONS.products)
const products = [
{ name: "王者荣耀皮肤礼包", description: "稀有皮肤随机礼包", image: "/product-skin-1.jpg", images: ["/product-skin-1.jpg"], category: "skin", game: "王者荣耀", price: 199, originalPrice: 299, stock: 1000, sales: 5680, rating: 4.8, tags: ["热销", "限定"], status: "active", createdAt: "2023-01-01", updatedAt: now() },
{ name: "电竞机械键盘", description: "青轴机械键盘RGB背光", image: "/product-keyboard.jpg", images: ["/product-keyboard.jpg"], category: "peripheral", price: 299, originalPrice: 399, stock: 500, sales: 2356, rating: 4.9, tags: ["外设", "推荐"], status: "active", createdAt: "2023-02-01", updatedAt: now() },
{ name: "游戏鼠标垫", description: "超大电竞鼠标垫", image: "/product-mousepad.jpg", images: ["/product-mousepad.jpg"], category: "peripheral", price: 59, originalPrice: 99, stock: 2000, sales: 8956, rating: 4.7, tags: ["热销"], status: "active", createdAt: "2023-03-01", updatedAt: now() },
]
await productsColl.insertMany(products)
console.log("[Mongo] products:", products.length)
// 9. 游戏点卡
const pointCardsColl = db.collection(COLLECTIONS.gamePointCards)
const pointCards = [
{ game: "王者荣耀", gameId: 1, gameLogo: "/wzry.jpg", name: "点券充值", description: "官方点券直充", faceValue: 100, price: 98, discount: 0.98, stock: 9999, sales: 12568, deliveryType: "instant", instructions: "请提供游戏账号", status: "active", createdAt: "2023-01-01" },
{ game: "英雄联盟", gameId: 2, gameLogo: "/lol.jpg", name: "点券充值", description: "官方点券直充", faceValue: 100, price: 97, discount: 0.97, stock: 9999, sales: 9856, deliveryType: "instant", instructions: "请提供游戏账号", status: "active", createdAt: "2023-01-01" },
{ game: "原神", gameId: 4, gameLogo: "/ys.jpg", name: "创世结晶", description: "官方充值", faceValue: 648, price: 628, discount: 0.97, stock: 9999, sales: 15689, deliveryType: "instant", instructions: "请提供UID", status: "active", createdAt: "2023-01-01" },
]
await pointCardsColl.insertMany(pointCards)
console.log("[Mongo] gamePointCards:", pointCards.length)
console.log("[Mongo] 种子数据写入完成")
}
async function main() {
try {
await ensureCollections()
await ensureIndexes()
await seed()
} finally {
await closeMongo()
}
}
main().catch((e) => {
console.error(e)
process.exit(1)
})