# seed_data.py — 丰富示例数据填充(仅在空库时执行一次) # 为每个工作台生成 > 1 亿的总规模,覆盖万/十万/百万/千万量级 import json import random random.seed(42) from datetime import date from db import db, _exec, one TENANTS = ["科普·无界", "科研·无界", "医患·无界", "MCN·无界", "学会·无界"] # 每个工作台的差异化客户和项目模板 TENANT_CUSTOMERS = { "科普·无界": [ ("信达生物", ["肿瘤免疫科普年度框架", "信迪利单抗医生教育", "CSCO卫星会项目", "患者随访管理系统"]), ("百利天恒", ["BL-B01D1上市前教育", "双抗药物科普专区", "数字人患教视频"]), ("齐鲁制药", ["多产品线医生教育", "安可达学术推广", "基层医疗科普巡讲"]), ("天广实生物", ["血液肿瘤科普项目", "CD20单抗学术推广"]), ("复星医药", ["复宏汉霖学术年会", "CAR-T患者教育"]), ], "科研·无界": [ ("北京协和医院", ["临床研究数据采集系统", "罕见病队列研究", "AI辅助诊断验证"]), ("中国人民解放军总医院", ["战场创伤数据平台", "远程会诊系统"]), ("复旦大学附属华山医院", ["脑卒中AI预警系统", "神经内科临床研究"]), ("中山大学肿瘤防治中心", ["鼻咽癌早筛项目", "真实世界研究平台"]), ("四川大学华西医院", ["精准医学大数据平台", "基层科研能力提升"]), ], "医患·无界": [ ("平安好医生", ["在线问诊科普内容", "慢病管理专区", "随访SOP标准化"]), ("微医集团", ["互联网医院患教系统", "云药房科普推送"]), ("丁香园", ["医生社区运营升级", "用药助手科普专区"]), ("圆心科技", ["药房患者教育", "DTP药房随访管理", "罕见病用药指导"]), ("国药控股", ["国药患者管理平台", "肿瘤药房随访系统"]), ], "MCN·无界": [ ("抖音健康", ["医学IP孵化矩阵", "短视频科普内容制作", "健康直播运营"]), ("快手健康", ["医生个人IP打造", "快手健康科普专区"]), ("小红书医美", ["皮肤健康科普矩阵", "医美科普合规审核"]), ("B站知识区", ["深度科普纪录片", "医学动画制作"]), ("微信视频号", ["医生科普直播运营", "企业微信科普推送"]), ], "学会·无界": [ ("中华医学会", ["学术年会数字化平台", "继续教育学分系统", "基层医生培训"]), ("中国医师协会", ["医师定考管理系统", "专科医师培训平台"]), ("中国抗癌协会", ["肿瘤科普万里行", "CACA指南推广"]), ("中国药学会", ["合理用药科普平台", "药师继续教育"]), ("中华护理学会", ["护理科研能力提升", "专科护士培训系统"]), ], } # 签约金额模板:每个工作台的千万/百万/十万/万级别项目的签约金额 def generate_sign_amounts(): amounts = [] # 千万级:2个(4000-7000万) amounts.append(random.randint(4500, 7000) * 10000) amounts.append(random.randint(4000, 6500) * 10000) # 百万级:4个(400-980万) for _ in range(4): amounts.append(random.randint(400, 980) * 10000) # 十万级:4个(30-98万) for _ in range(4): amounts.append(random.randint(30, 98) * 10000) # 万级:3个(3-10万) for _ in range(3): amounts.append(random.randint(3, 10) * 10000) return sorted(amounts, reverse=True) # 生成 budget_data JSON(每月确收/毛利/回款) def make_budget_data(sign_amount, signed_month, status): """生成12个月的预算数据""" months = [] start_m = int(signed_month.split("-")[1]) if signed_month else 1 rev_total = sign_amount if status == "已签约" else int(sign_amount * random.uniform(0.3, 0.7)) gross_rate = random.uniform(0.25, 0.55) payment_rate = random.uniform(0.7, 0.95) for i in range(12): m = (start_m + i - 1) % 12 + 1 yr = 2026 + (start_m + i - 1) // 12 month_key = f"{yr}-{m:02d}" # 越往后确收越多 progress = min(1.0, (i + 1) / max(1, random.randint(3, 8))) rev = round(rev_total * progress * random.uniform(0.85, 1.15)) gross = round(rev * gross_rate * random.uniform(0.9, 1.1)) payment = round(rev * payment_rate * random.uniform(0.85, 1.15)) cost = round(rev * random.uniform(0.3, 0.5)) paid = round(cost * random.uniform(0.8, 1.0)) months.append({ "month": month_key, "rev": rev, "gross": gross, "payment": payment, "cost": cost, "paid": paid, }) return json.dumps(months) # 生成 expense_data(平台费用) def make_expense_data(): """生成若干条费用记录""" items = [] expense_types = ["平台采购", "人力成本", "研发费用", "通用费用", "奖金"] for q in range(1, 7): for et in random.sample(expense_types, random.randint(2, 4)): month_str = f"2026-{q:02d}" amount = random.randint(5000, 150000) incurred = int(amount * random.uniform(0.6, 1.0)) items.append({"month": month_str, "expense_type": et, "amount": amount, "incurred": incurred}) return json.dumps(items) def seed_db(): """填充丰富示例数据""" conn = db() try: if one(conn, "SELECT id FROM sales_leads LIMIT 1"): return today = date.today().isoformat() pf_ids = {} # tenant -> [project_finance_ids] for tenant in TENANTS: customers = TENANT_CUSTOMERS[tenant] amounts = generate_sign_amounts() cust_idx = 0 for i, sign_amount in enumerate(amounts): cust_name, projects = customers[cust_idx % len(customers)] proj_name = projects[i % len(projects)] if i < len(projects) else f"{cust_name} 项目{i+1}" cust_idx += i % 3 # 70% 已签约, 30% 待签约 status = "已签约" if random.random() < 0.7 else "待签约" sign_month = f"2026-{random.randint(1, 6):02d}" if status == "已签约" else "" project_code = f"{tenant[:2]}-2026-{i+1:03d}" business_type = random.choice(["学术推广", "医生教育", "患者管理", "科研合作", "科普内容"]) # 如果签约,总额 = 签约额;否则为0 total_rev = int(sign_amount * random.uniform(0.8, 1.0)) if status == "已签约" else 0 total_gross = int(total_rev * random.uniform(0.25, 0.5)) if status == "已签约" else 0 total_payment = int(total_rev * random.uniform(0.7, 0.9)) if status == "已签约" else 0 total_cost = int(total_rev * random.uniform(0.3, 0.5)) if status == "已签约" else 0 total_paid = int(total_cost * random.uniform(0.7, 0.95)) if status == "已签约" else 0 budget_data = make_budget_data(sign_amount, sign_month, status) expense_data = make_expense_data() if status == "已签约" else "[]" task_data = json.dumps([ {"task": f"{proj_name} 项目启动", "due": f"2026-{min(12, 1+i//2):02d}-01", "status": "已完成" if i < 8 else "进行中"}, {"task": f"方案评审与确认", "due": f"2026-{min(12, 2+i//2):02d}-15", "status": "已完成" if i < 6 else "进行中"}, {"task": f"内容生产阶段", "due": f"2026-{min(12, 3+i//2):02d}-30", "status": "进行中"}, ]) cur = _exec(conn, """ INSERT INTO project_finances (tenant, project_id, business_type, customer_name, sign_amount, sign_month, status, sales_person, total_rev, total_gross, total_payment, total_cost, total_paid, budget_data, expense_data, task_data, project_code, start_date, end_date, task_type, task_count, service_fee_standard, project_manager, contact_name, contact_phone, other_info, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) """, ( tenant, f"PF-{tenant[:2]}-{i+1:04d}", business_type, cust_name, sign_amount, sign_month, status, f"销售{random.choice(['A','B','C','D'])}", total_rev, total_gross, total_payment, total_cost, total_paid, budget_data, expense_data, task_data, project_code, f"2026-{random.randint(1,3):02d}-01", f"2026-{random.randint(9,12):02d}-30", random.choice(["内容生产", "视频制作", "专家访谈", "学术会议", "患者教育"]), random.randint(10, 100), random.choice([800, 1000, 1200, 1500, 2000]), f"经理{random.choice(['A','B','C'])}", f"联系人{random.randint(1,20)}", f"1380000{random.randint(1000,9999)}", f"备注信息 {i+1}", today, today, )) # Store for later use pf_ids.setdefault(tenant, []).append((cur.lastrowid, proj_name, cust_name, status)) # operation_projects: 每个工作台 3-5 个 op_count = random.randint(3, 5) for j in range(op_count): pf_row = random.choice(pf_ids[tenant]) cur2 = _exec(conn, """ INSERT INTO operation_projects (tenant, project_name, project_version, project_type, project_status, current_stage, owner, start_date, end_date, target_customer, customer_need, expected_contract_amount, expected_sign_date, sign_probability, next_action, sop_stage, execution_progress, current_deliverable, notes) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) """, ( tenant, f"{pf_row[1]} 运营方案", "v1.0", "execution" if random.random() < 0.6 else "opportunity", "SOP 执行中" if random.random() < 0.6 else "方案已提交", random.choice(["商务推进", "内容生产", "渠道分发"]), f"OPC{random.randint(1,5)}", "2026-06-01", "2026-12-31", pf_row[2], "科普内容项目执行与管理", pf_row[0] if pf_row[3] == "已签约" else random.randint(50, 300) * 10000, "2026-06", 70 + random.randint(0, 30), "补齐版本要求文件并更新下一节点", "SOP 执行", random.randint(30, 80), "当前交付物 v1.0", "运营备注", )) _exec(conn, """ INSERT INTO follow_up_records (target_type, target_id, followed_at, content, next_action, follower) VALUES (?,?,?,?,?,?) """, ( "operation", cur2.lastrowid, today, f"运营项目跟进:{pf_row[1]},当前进度正常", "继续推进下一里程碑", f"销售{random.choice(['A','B'])}", )) # expense_records: 每个工作台 15-20 条 expense_count = random.randint(15, 20) expense_types = ["通用费用", "平台采购", "人力成本", "研发费用", "奖金", "其他"] for j in range(expense_count): et = random.choice(expense_types) month_str = f"2026-{random.randint(1, 6):02d}" amount = random.randint(5000, 500000) incurred = int(amount * random.uniform(0.5, 1.0)) _exec(conn, """ INSERT INTO expense_records (tenant, expense_type, expense_month, amount, incurred_amount, notes) VALUES (?,?,?,?,?,?) """, ( tenant, et, month_str, amount, incurred, f"{et} - {random.choice(['季度预算', '紧急支出', '常规费用', '项目费用'])}", )) print(f"[seed] {tenant}: {len(amounts)} 项目, {op_count} 运营项目, {expense_count} 费用记录") conn.commit() # 提交所有工作台的核心数据 # 全域数据:sales_leads 对所有 tenant 可见 global_sales = [ ("齐鲁制药", "P0", "跟进中", "多产品线科普年度框架"), ("百利天恒", "P0", "方案中", "BL-B01D1 上市前医生教育"), ("信达生物", "P0", "已签约", "现有科普项目升级/续约"), ("三生制药", "P1", "待跟进", "多科室医生教育+患者科普"), ("天广实生物", "P1", "待跟进", "血液肿瘤医生教育机会"), ] for customer, priority, status, note in global_sales: cur = _exec(conn, "INSERT INTO sales_leads (target_customer, priority, status, created_at) VALUES (?,?,?,?)", (customer, priority, status, today), ) _exec(conn, "INSERT INTO follow_up_records (target_type,target_id,followed_at,content,next_action,follower) VALUES (?,?,?,?,?,?)", ("sales", cur.lastrowid, today, note, "明确下一次沟通", "销售A"), ) # 全域 business_proposals cur = _exec(conn, "INSERT INTO business_proposals (customer_or_project_name,version,description,status,created_date, tenant) VALUES (?,?,?,?,?,?)", ("信达生物", "v1.5", "信达科普项目续约与报价方案", "已提交客户", "2026-05-28", "科普·无界"), ) proposal_id = cur.lastrowid # 全域 product_versions products = [ ("妙手医生服务小程序", "v1.1", "视频任务增强 + 积分商城", "2026-Q3", "规划中", "P1"), ("数字化营销后台管理系统", "v1.2", "运营数据看板 + 智能审核", "2026-Q3", "设计中", "P0"), ("妙手患者服务", "v0.5", "科普浏览 + 医生主页 MVP", "2026-Q3", "规划中", "P2"), ("数字人内容平台", "v0.1", "基础数字人视频生成 MVP", "2026-Q3", "规划中", "P2"), ("渠道分发引擎", "v1.0", "六渠道统一分发", "2027-Q1", "规划中", "P1"), ] for p in products: cur = _exec(conn, "INSERT INTO product_versions (product_name,version,version_goal,launch_date,status,priority,tenant) VALUES (?,?,?,?,?,?,?)", (*p, "科普·无界"), ) _exec(conn, "INSERT INTO follow_up_records (target_type,target_id,followed_at,content,next_action,follower) VALUES (?,?,?,?,?,?)", ("product", cur.lastrowid, today, f"{p[0]} {p[1]}:{p[2]}", "按路线图推进", "产品经理"), ) conn.commit() print("[seed] 丰富示例数据已填充") finally: conn.close()