190 lines
7.4 KiB
Python
190 lines
7.4 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import date, timedelta
|
|
from typing import Any
|
|
|
|
from .seed_data import CITIES
|
|
|
|
|
|
PERSON_NAMES = [
|
|
"林晓雨",
|
|
"陈浩然",
|
|
"王思琪",
|
|
"张明远",
|
|
"李雅雯",
|
|
"刘子轩",
|
|
"赵可",
|
|
"周雨桐",
|
|
"吴俊杰",
|
|
"郑诗涵",
|
|
"孙宇航",
|
|
"许念",
|
|
]
|
|
|
|
ROLES = ["产品设计师", "独立开发者", "内容创作者", "远程运营", "自由摄影师", "跨境电商", "AI 创业者", "用户研究员"]
|
|
|
|
|
|
def _future_date(index: int) -> str:
|
|
return (date(2026, 7, 10) + timedelta(days=index * 3)).strftime("%Y-%m-%d")
|
|
|
|
|
|
ENHANCED_MEETUPS: list[dict[str, Any]] = [
|
|
{
|
|
"city": city["name"],
|
|
"emoji": city.get("icon", "📍"),
|
|
"date": _future_date(idx),
|
|
"time": "19:00" if idx % 2 else "15:00",
|
|
"venue": f"{city['name']}远程工作者周会",
|
|
"address": f"{city['name']}核心生活区共享空间",
|
|
"description": f"围绕{city['name']}的租房、办公、社群和长期停留经验做一次小规模圆桌交流。",
|
|
"rsvpCount": max(6, int(city["nomadsNow"] * 0.025)),
|
|
"gradientFrom": city["gradientFrom"],
|
|
"gradientTo": city["gradientTo"],
|
|
"attendees": [
|
|
{"name": PERSON_NAMES[idx % len(PERSON_NAMES)], "photo": f"https://i.pravatar.cc/150?img={(idx % 60) + 1}"},
|
|
{"name": PERSON_NAMES[(idx + 3) % len(PERSON_NAMES)], "photo": f"https://i.pravatar.cc/150?img={((idx + 3) % 60) + 1}"},
|
|
],
|
|
"isUpcoming": idx % 5 != 0,
|
|
"status": "published",
|
|
"mode": "online" if idx % 6 == 0 else "hybrid" if idx % 4 == 0 else "offline",
|
|
"maxAttendees": 80 if idx % 6 == 0 else 36 if idx % 4 == 0 else 24,
|
|
"organizer": f"{city['name']}城市主理人",
|
|
"accessLevel": "vip" if idx % 6 == 0 else "members" if idx % 4 == 0 else "public",
|
|
"meetingProvider": "mirotalk" if idx % 4 == 0 or idx % 6 == 0 else "",
|
|
"mirotalkRoom": f"nomadcna-{city['slug']}-remote-roundtable" if idx % 4 == 0 or idx % 6 == 0 else "",
|
|
"meetingUrl": "",
|
|
"replayUrl": "",
|
|
"features": ["group_video", "screen_share", "whiteboard", "host_controls"] if idx % 4 == 0 or idx % 6 == 0 else [],
|
|
}
|
|
for idx, city in enumerate(CITIES, start=1)
|
|
]
|
|
|
|
|
|
ENHANCED_DISCUSSIONS: list[dict[str, Any]] = [
|
|
{
|
|
"title": f"{city['name']}远程办公和短租落地经验汇总",
|
|
"author": PERSON_NAMES[idx % len(PERSON_NAMES)],
|
|
"city": city["name"],
|
|
"tags": [city["name"], "落地指南", "远程工作"],
|
|
"replies": 8 + idx * 2,
|
|
"views": 600 + idx * 137,
|
|
"excerpt": f"整理{city['name']}适合视频会议的住区、稳定网络和本地社群入口。",
|
|
}
|
|
for idx, city in enumerate(CITIES, start=1)
|
|
]
|
|
|
|
|
|
ENHANCED_GIGS: list[dict[str, Any]] = [
|
|
{
|
|
"title": f"补充{city['name']}数字游民城市资料",
|
|
"category": ["内容", "调研", "摄影", "活动"][idx % 4],
|
|
"budget": 300 + (idx % 6) * 200,
|
|
"location": city["name"] if idx % 3 == 0 else "远程",
|
|
"description": f"提交{city['name']}共享办公、短租、公交通勤和社群活动信息,要求有来源和照片。",
|
|
"status": "open",
|
|
}
|
|
for idx, city in enumerate(CITIES, start=1)
|
|
]
|
|
|
|
|
|
ENHANCED_PROFILES: list[dict[str, Any]] = [
|
|
{
|
|
"name": PERSON_NAMES[idx % len(PERSON_NAMES)],
|
|
"age": 24 + (idx % 13),
|
|
"location": city["name"],
|
|
"tags": [ROLES[idx % len(ROLES)], "数字游民", city["name"], "可线下见面"],
|
|
"bio": f"目前在{city['name']}远程工作,关注高质量生活、稳定产出和本地社群连接。",
|
|
"photo": f"https://i.pravatar.cc/150?img={(idx % 60) + 1}",
|
|
}
|
|
for idx, city in enumerate(CITIES, start=1)
|
|
]
|
|
|
|
|
|
SERVICES: list[dict[str, Any]] = [
|
|
{
|
|
"slug": "remote-health-insurance",
|
|
"title": "远程工作者医疗与旅行保障",
|
|
"titleEn": "Remote Health & Travel Coverage",
|
|
"icon": "🛡️",
|
|
"description": "覆盖国内旅居、短期出境、设备丢失和紧急医疗咨询,适合频繁换城市的远程工作者。",
|
|
"descriptionEn": "Coverage for domestic stays, short overseas trips, device loss, and urgent medical advice.",
|
|
"features": ["国内外医疗协助", "设备丢失补偿", "7x24 中文支持", "城市风险提醒"],
|
|
"price": 15,
|
|
"priceLabel": "¥15/天起",
|
|
"category": "保障",
|
|
"status": "published",
|
|
"gradientFrom": "#10b981",
|
|
"gradientTo": "#0f766e",
|
|
},
|
|
{
|
|
"slug": "coworking-pass",
|
|
"title": "共享办公通行证",
|
|
"titleEn": "Coworking Pass",
|
|
"icon": "💻",
|
|
"description": "为热门城市整理可视频会议、可日租、可社群活动的空间,并提供预订入口。",
|
|
"descriptionEn": "Workspace list and booking entry for day-pass and video-call friendly spaces.",
|
|
"features": ["城市空间清单", "日租/月租筛选", "视频会议友好", "会员折扣"],
|
|
"price": 99,
|
|
"priceLabel": "¥99/月起",
|
|
"category": "办公",
|
|
"status": "published",
|
|
"gradientFrom": "#2563eb",
|
|
"gradientTo": "#0891b2",
|
|
},
|
|
{
|
|
"slug": "landing-concierge",
|
|
"title": "城市落地顾问",
|
|
"titleEn": "City Landing Concierge",
|
|
"icon": "🧭",
|
|
"description": "帮你把预算、气候、网络、租房、社群入口整理成 30 天落地清单。",
|
|
"descriptionEn": "A 30-day landing checklist based on budget, climate, internet, housing, and community.",
|
|
"features": ["落地清单", "短租建议", "同城活动", "社群引荐"],
|
|
"price": 299,
|
|
"priceLabel": "¥299/次",
|
|
"category": "落地",
|
|
"status": "published",
|
|
"gradientFrom": "#f97316",
|
|
"gradientTo": "#ef4444",
|
|
},
|
|
]
|
|
|
|
|
|
ROUTES: list[dict[str, Any]] = [
|
|
{
|
|
"slug": "yunnan-slow-life",
|
|
"title": "云南慢生活线",
|
|
"titleEn": "Yunnan Slow Life",
|
|
"citySlugs": ["dali", "lijiang", "kunming"],
|
|
"durationDays": 21,
|
|
"budget": 12000,
|
|
"description": "适合内容创作者、设计师和希望低成本试住的远程工作者。",
|
|
"descriptionEn": "For creators and designers seeking a slower, lower-cost stay.",
|
|
"stops": ["大理 10 天", "丽江 5 天", "昆明 6 天"],
|
|
"status": "published",
|
|
},
|
|
{
|
|
"slug": "bay-area-builder",
|
|
"title": "湾区创业线",
|
|
"titleEn": "Bay Area Builder Route",
|
|
"citySlugs": ["shenzhen", "guangzhou", "zhuhai"],
|
|
"durationDays": 14,
|
|
"budget": 16000,
|
|
"description": "适合创业者、硬件团队和需要商务连接的远程工作者。",
|
|
"descriptionEn": "For startup builders and teams needing business access.",
|
|
"stops": ["深圳 7 天", "广州 4 天", "珠海 3 天"],
|
|
"status": "published",
|
|
},
|
|
{
|
|
"slug": "jiangnan-internet",
|
|
"title": "江南互联网线",
|
|
"titleEn": "Jiangnan Internet Route",
|
|
"citySlugs": ["hangzhou", "shanghai", "suzhou", "nanjing"],
|
|
"durationDays": 18,
|
|
"budget": 18000,
|
|
"description": "适合产品、运营、增长、AI 和跨境团队做城市比较。",
|
|
"descriptionEn": "For product, growth, AI, and cross-border teams comparing cities.",
|
|
"stops": ["杭州 6 天", "上海 5 天", "苏州 3 天", "南京 4 天"],
|
|
"status": "published",
|
|
},
|
|
]
|