Files
server-core/app/infrastructure/seed.py
T

1038 lines
56 KiB
Python
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.
# -*- coding: utf-8 -*-
"""幂等种子数据:角色 / 权限 / 角色权限矩阵 / 区域 / 组织 / 演示用户。
在 ``app.db.init_db()`` 之后调用;仅当 ``roles`` 表为空时才写入,
避免覆盖已有数据。
"""
from __future__ import annotations
import json
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from .models import (
AuditLog,
ContentItem,
FinanceRecord,
InvestmentIntent,
InvestorPreference,
Message,
Notification,
OpcProfile,
OpcTask,
Organization,
OrganizationMember,
Permission,
PortalDashboard,
PortalPage,
Region,
Roadshow,
RoadshowRegistration,
Role,
RolePermission,
ServiceProvider,
ServiceReferral,
SessionToken,
SubsidyApplication,
SystemConfig,
Task,
TaskCategory,
TrainingEnrollment,
User,
Agent,
)
from .repositories import AGENT_SEED, new_id, utcnow_iso
from .security import hash_password
# ---------------------------------------------------------------------------
# 角色
# ---------------------------------------------------------------------------
ROLES = [
# 业务角色
("opc_member", "OPC超级个体", "business"),
("carrier", "创业载体(园区)", "business"),
("enterprise", "甲方企业", "business"),
("provider", "服务商", "business"),
("government", "政务端", "business"),
("operator", "平台运营方", "business"),
# 政务子级(继承 government 通用权限)
("government|gov_province", "省级政务", "government-level"),
("government|gov_city", "市级政务", "government-level"),
("government|gov_district", "区县级政务", "government-level"),
("government|gov_org_admin", "政务组织机构管理员", "government-level"),
("government|gov_op_account", "政务操作账号", "government-level"),
# 运营方内部子角色
("operator|op_super_admin", "超级管理员", "operator-internal"),
("operator|op_admin", "运营管理员", "operator-internal"),
("operator|op_customer_service", "客服管理员", "operator-internal"),
("operator|op_finance", "财务管理员", "operator-internal"),
("operator|op_analyst", "数据分析师", "operator-internal"),
("operator|op_techops", "技术运维", "operator-internal"),
# 企业 / 载体 / 服务商 / OPC 端口内子角色
("enterprise|admin", "企业管理员", "business"),
("enterprise|operator", "企业操作者", "business"),
("carrier|admin", "园区管理员", "business"),
("carrier|operator", "园区操作者", "business"),
("provider|admin", "服务商管理员", "business"),
("provider|operator", "服务商操作者", "business"),
("opc_member|certified", "认证OPC", "business"),
("opc_member|independent", "独立OPC", "business"),
# 投资人端口内子角色
("investor", "投资人", "business"),
("investor|org_director", "机构投资总监", "business"),
("investor|org_manager", "机构投资经理", "business"),
("investor|personal", "个人投资人", "business"),
# 开放平台端口内子角色
("developer", "开发者", "business"),
("developer|dev_individual", "个人开发者", "business"),
("developer|dev_org_admin", "机构开发者管理员", "business"),
("developer|dev_member", "开发者成员", "business"),
]
# ---------------------------------------------------------------------------
# 权限
# ---------------------------------------------------------------------------
PERMISSIONS = [
# 各门户菜单
("menu:opc_dashboard", "OPC 门户", "menu", "opc"),
("menu:carrier_dashboard", "载体门户", "menu", "carrier"),
("menu:enterprise_dashboard", "企业门户", "menu", "enterprise"),
("menu:provider_dashboard", "服务商门户", "menu", "provider"),
("menu:government_dashboard", "政务门户", "menu", "government"),
("menu:operator_dashboard", "运营门户", "menu", "operator"),
("menu:investor_dashboard", "投资人门户", "menu", "investor"),
("menu:investor_projects", "投资人·项目库", "menu", "investor"),
("menu:investor_roadshow", "投资人·路演活动", "menu", "investor"),
("menu:investor_training", "投资人·投融资培训", "menu", "investor"),
("menu:developer_dashboard", "开发者门户", "menu", "developer"),
("menu:developer_apps", "开发者·我的应用", "menu", "developer"),
("menu:developer_plugins", "开发者·我的插件", "menu", "developer"),
("menu:developer_skills", "开发者·技能市场", "menu", "developer"),
# 管理菜单
("menu:admin_user_mgmt", "用户管理", "menu", "admin"),
("menu:admin_role_mgmt", "角色权限管理", "menu", "admin"),
("menu:gov_data", "政务数据", "menu", "government"),
("menu:audit", "审计日志", "menu", "audit"),
("menu:settlements", "结算台账", "menu", "operator"),
# 操作
("action:user.assign_role", "分配角色", "action", "admin"),
("action:user.disable", "禁用/启用用户", "action", "admin"),
("action:role.grant_perm", "配置角色权限", "action", "admin"),
("action:org.manage", "管理组织", "action", "org"),
("action:data.export", "数据导出", "action", "data"),
("action:audit.view", "查看审计", "action", "audit"),
("action:task.manage", "任务管理(建改)", "action", "operator"),
("action:provider.manage", "服务商管理(建改)", "action", "operator"),
("action:content.manage", "内容管理(建发)", "action", "operator"),
("action:config.manage", "系统配置(修改)", "action", "operator"),
("action:settlement.manage", "结算管理", "action", "operator"),
# 平台运营(operator)功能页
("menu:admin_courses", "课程管理", "menu", "admin"),
("menu:admin_activities", "活动管理", "menu", "admin"),
("menu:admin_bookings", "报名管理", "menu", "admin"),
("menu:admin_tests", "测评管理", "menu", "admin"),
("menu:admin_surveys", "调研结果", "menu", "admin"),
("menu:admin_policies", "政策结果", "menu", "admin"),
("menu:admin_plans", "流程启动", "menu", "admin"),
("menu:admin_compute", "算力管理", "menu", "admin"),
("menu:admin_content", "资讯管理", "menu", "admin"),
("menu:admin_content_review", "资讯审核", "menu", "admin"),
("menu:admin_tasks", "任务管理", "menu", "admin"),
("menu:admin_providers", "服务商管理", "menu", "admin"),
("menu:admin_config", "系统配置", "menu", "admin"),
("menu:admin_park", "平台园区", "menu", "admin"),
("menu:admin_park_screens", "屏幕绑定", "menu", "admin"),
("menu:opc_cert", "OPC认证", "menu", "admin"),
("menu:admission", "入驻审核", "menu", "admin"),
("menu:park_transfer", "转园审核", "menu", "admin"),
# 园区(carrier)工作台
("menu:park_screens", "屏幕管理", "menu", "carrier"),
("menu:park_screen", "大屏控制台", "menu", "carrier"),
("menu:park_companies", "企业管理", "menu", "carrier"),
("menu:park_users", "用户管理", "menu", "carrier"),
("menu:park_content", "资讯管理", "menu", "carrier"),
("menu:park_kb", "园区知识库", "menu", "carrier"),
("menu:park_agent", "园区智能体", "menu", "carrier"),
("menu:park_data", "大屏数据", "menu", "carrier"),
("menu:park_vision", "视频识别", "menu", "carrier"),
("menu:park_admissions", "入园申请", "menu", "carrier"),
("menu:park_transfers", "转园申请", "menu", "carrier"),
]
# role_id -> [permission_id]
ROLE_PERMISSIONS: dict[str, list[str]] = {
"opc_member": ["menu:opc_dashboard"],
"carrier": [
"menu:carrier_dashboard", "action:org.manage",
"menu:park_screens", "menu:park_screen", "menu:park_companies", "menu:park_users", "menu:park_content",
"menu:park_kb",
"menu:park_agent", "menu:park_data", "menu:park_vision",
"menu:park_admissions", "menu:park_transfers",
],
"enterprise": ["menu:enterprise_dashboard", "action:org.manage"],
"provider": [
"menu:provider_dashboard", "action:org.manage", "action:data.export",
],
"government": ["menu:government_dashboard", "menu:gov_data"],
"government|gov_province": ["action:data.export"],
"government|gov_city": ["action:data.export"],
"government|gov_district": ["action:data.export"],
"government|gov_org_admin": ["action:org.manage"],
"government|gov_op_account": ["action:data.export"],
"operator": [
"menu:operator_dashboard",
"menu:admin_user_mgmt", "menu:admin_role_mgmt", "menu:audit", "menu:settlements",
"menu:admin_courses", "menu:admin_activities", "menu:admin_bookings", "menu:admin_tests",
"menu:admin_surveys", "menu:admin_policies", "menu:admin_plans", "menu:admin_compute",
"menu:admin_content", "menu:admin_content_review", "menu:admin_tasks", "menu:admin_providers", "menu:admin_config",
"menu:admin_park", "menu:admin_park_screens", "menu:opc_cert", "menu:admission", "menu:park_transfer",
"action:user.assign_role", "action:user.disable", "action:role.grant_perm",
"action:org.manage", "action:data.export", "action:audit.view",
"action:task.manage", "action:provider.manage", "action:content.manage",
"action:config.manage", "action:settlement.manage",
],
"operator|op_super_admin": [
"menu:admin_user_mgmt", "menu:admin_role_mgmt", "menu:audit", "menu:settlements",
"action:user.assign_role", "action:user.disable", "action:role.grant_perm",
"action:org.manage", "action:data.export", "action:audit.view",
"action:task.manage", "action:provider.manage", "action:content.manage",
"action:config.manage", "action:settlement.manage",
],
"operator|op_admin": [
"menu:admin_user_mgmt", "menu:admin_role_mgmt", "menu:audit", "menu:settlements",
"action:user.assign_role", "action:user.disable",
"action:org.manage", "action:data.export", "action:audit.view",
"action:task.manage", "action:provider.manage", "action:content.manage",
"action:config.manage", "action:settlement.manage",
],
"operator|op_customer_service": [
"action:data.export", "action:task.manage", "action:provider.manage",
"action:content.manage",
],
"operator|op_finance": [
"menu:settlements", "action:data.export", "action:settlement.manage",
],
"operator|op_analyst": ["menu:audit", "action:data.export", "action:audit.view"],
"operator|op_techops": [
"menu:admin_user_mgmt", "action:org.manage", "action:data.export",
"action:config.manage",
],
"enterprise|admin": ["menu:enterprise_dashboard", "action:org.manage"],
"enterprise|operator": ["menu:enterprise_dashboard"],
"carrier|admin": ["menu:carrier_dashboard", "action:org.manage"],
"carrier|operator": ["menu:carrier_dashboard"],
"provider|admin": [
"menu:provider_dashboard", "action:org.manage", "action:data.export",
],
"provider|operator": ["menu:provider_dashboard", "action:data.export"],
"opc_member|certified": ["menu:opc_dashboard"],
"opc_member|independent": ["menu:opc_dashboard"],
"investor": ["menu:investor_dashboard"],
"investor|org_director": [
"menu:investor_dashboard", "menu:investor_projects", "menu:investor_roadshow", "menu:investor_training",
"action:preference.manage", "action:project.view", "action:intent.manage",
"action:roadshow.publish", "action:roadshow.host", "action:invest.decide",
],
"investor|org_manager": [
"menu:investor_dashboard", "menu:investor_projects", "menu:investor_roadshow",
"action:preference.manage", "action:project.view", "action:intent.manage", "action:roadshow.attend",
],
"investor|personal": [
"menu:investor_dashboard", "menu:investor_projects", "menu:investor_roadshow", "menu:investor_training",
"action:preference.manage", "action:project.view", "action:intent.manage",
"action:roadshow.attend", "action:roadshow.register",
],
"developer": ["menu:developer_dashboard"],
"developer|dev_individual": [
"menu:developer_dashboard", "menu:developer_apps", "menu:developer_plugins", "menu:developer_skills",
"action:app.create", "action:app.publish", "action:plugin.create", "action:skill.publish",
],
"developer|dev_org_admin": [
"menu:developer_dashboard", "menu:developer_apps", "menu:developer_plugins", "menu:developer_skills",
"action:app.create", "action:app.publish", "action:app.manage", "action:plugin.create", "action:skill.publish", "action:apikey.manage",
],
"developer|dev_member": [
"menu:developer_dashboard", "menu:developer_apps",
"action:app.create",
],
}
# ---------------------------------------------------------------------------
# 区域(省/市/区县 示例树)
# ---------------------------------------------------------------------------
REGIONS = [
("r_prov_yn", "云南省", "province", None),
("r_city_km", "昆明市", "city", "r_prov_yn"),
("r_city_qj", "曲靖市", "city", "r_prov_yn"),
("r_dist_pl", "盘龙区", "district", "r_city_km"),
("r_dist_wh", "五华区", "district", "r_city_km"),
("r_dist_ql", "麒麟区", "district", "r_city_qj"),
]
# ---------------------------------------------------------------------------
# 组织(甲方企业 / 创业载体 / 服务商)
# ---------------------------------------------------------------------------
ORGANIZATIONS = [
("o_ent_001", "云南某某甲方企业", "enterprise", "r_dist_pl", None),
("o_car_001", "滇池创业园", "carrier", "r_dist_wh", None),
("o_pro_001", "云超财税服务所", "provider", "r_city_km", None),
("o_ent_prov", "省级示范企业", "enterprise", "r_prov_yn", None),
]
# ---------------------------------------------------------------------------
# 演示用户(role/sub_role/org/region 各异,用于 RBAC 演示与测试)
# ---------------------------------------------------------------------------
DEMO_USERS = [
# id, username, nickname, password, role, sub_role, org_id, region_id
("u_demo_01", "pine", "云超服小助手", "123456", "operator", "op_super_admin", None, "r_prov_yn"),
("u_gov_prov", "gov_prov", "省政务账号", "123456", "government", "gov_province", None, "r_prov_yn"),
("u_gov_dist", "gov_dist", "区县政务账号", "123456", "government", "gov_district", None, "r_dist_wh"),
("u_ent_01", "ent01", "甲方企业账号", "123456", "enterprise", None, "o_ent_001", "r_dist_pl"),
("u_car_01", "car01", "园区运营账号", "123456", "carrier", None, "o_car_001", "r_dist_wh"),
("u_pro_01", "pro01", "服务商账号", "123456", "provider", None, "o_pro_001", "r_city_km"),
("u_op_an", "op_analyst", "运营数据分析", "123456", "operator", "op_analyst", None, "r_prov_yn"),
("u_op_admin", "op_admin", "运营管理员", "123456", "operator", "op_admin", None, "r_prov_yn"),
("u_op_cs", "op_cs", "运营客服", "123456", "operator", "op_customer_service", None, "r_prov_yn"),
("u_op_fin", "op_fin", "运营财务", "123456", "operator", "op_finance", None, "r_prov_yn"),
("u_op_tech", "op_tech", "运营运维", "123456", "operator", "op_techops", None, "r_prov_yn"),
("u_opc_01", "opc01", "OPC个人创业者", "123456", "opc_member", None, None, "r_dist_wh"),
("u_opc_02", "opc02", "OPC个体工商户", "123456", "opc_member", None, None, "r_dist_pl"),
("u_inv_01", "inv01", "投资人账号", "123456", "investor", "personal", None, "r_prov_yn"),
("u_inv_02", "inv02", "机构投资人", "123456", "investor", "org_director", None, "r_prov_yn"),
]
async def _add_agent(session: AsyncSession, seed: dict, user_id: str, port: str | None, now: str) -> None:
"""幂等播种单个智能体:SQLite INSERT OR IGNORE(id,user_id,port) 冲突跳过),杜绝 UNIQUE 抛错。"""
from sqlalchemy.dialects.sqlite import insert as sqlite_insert
port_val = port or "" # agents.port NOT NULL;无端口身份用 ""
stmt = sqlite_insert(Agent).values(
id=seed["id"], user_id=user_id, port=port_val, name=seed["name"],
description=seed["description"], language=seed.get("language", "zh"),
model_name=seed.get("model_name", ""), deletable=seed.get("deletable", True),
use_fixed_soul=seed.get("use_fixed_soul", False), created_at=now, updated_at=now,
).on_conflict_do_nothing(index_elements=["id", "user_id", "port"])
await session.execute(stmt)
async def seed_data(session: AsyncSession) -> None:
"""幂等种子:仅当 roles 表为空时写入全部基础数据;身份与 OPC 业务始终补种。"""
now = utcnow_iso()
existing = await session.scalar(select(Role.id).limit(1))
if existing is not None:
# 已初始化的库:仍补种 OPC 业务演示数据、账号身份与端口工作台(各自幂等)。
await _sync_permissions(session, now)
await _ensure_extra_demo_users(session, now)
await _seed_opc_business(session, now)
await _seed_task_categories(session, now)
await _seed_port_dashboards(session, now)
await _seed_market(session, now)
await _seed_port_pages(session, now)
await _seed_investor(session, now)
await _seed_ecosystem(session, now)
await _seed_org_members(session, now)
await session.commit()
return
session.add_all(
[Role(id=r[0], name=r[1], scope_type=r[2]) for r in ROLES]
)
session.add_all(
[
Permission(id=p[0], name=p[1], category=p[2], module=p[3])
for p in PERMISSIONS
]
)
for role_id, perms in ROLE_PERMISSIONS.items():
session.add_all(
[
RolePermission(role_id=role_id, permission_id=perm)
for perm in perms
]
)
session.add_all(
[
Region(id=r[0], name=r[1], level=r[2], parent_id=r[3], created_at=now)
for r in REGIONS
]
)
session.add_all(
[
Organization(
id=o[0], name=o[1], type=o[2], region_id=o[3],
parent_id=o[4], created_at=now,
)
for o in ORGANIZATIONS
]
)
for (uid, username, nickname, password, role, sub_role, org_id, region_id) in DEMO_USERS:
digest, salt = hash_password(password)
session.add(
User(
id=uid, username=username, nickname=nickname,
password_hash=digest, password_salt=salt,
role=role, sub_role=sub_role, org_id=org_id, region_id=region_id,
status="active", token_version=0, created_at=now, updated_at=now,
source="seed", auth_type="admin",
)
)
# 为每个用户播种默认 + QA 智能体(幂等按 (id,user_id,port=null) 防重)
for seed in AGENT_SEED:
await _add_agent(session, seed, uid, None, now)
await _seed_task_categories(session, now)
await _seed_operator_business(session, now)
await _seed_opc_business(session, now)
await _seed_port_dashboards(session, now)
await _seed_market(session, now)
await _seed_port_pages(session, now)
await _seed_investor(session, now)
await _seed_ecosystem(session, now)
await _seed_org_members(session, now)
await session.commit()
# ---------------------------------------------------------------------------
# 运营端业务演示数据(任务/服务商/内容/配置)
# ---------------------------------------------------------------------------
# 任务分类字典(顶层 35 类,取自 design/云超服平台/任务类别.json,幂等:表空才插)
_TASK_CATEGORY_NAMES = [
"平面设计", "移动端开发", "网站建设服务", "软件开发", "硬件开发", "知识产权",
"市场推广", "音视频", "动漫游戏设计", "UI设计", "工业设计与制造", "策划",
"写作和内容", "工程设计", "空间设计服务", "人力资源", "科技服务", "技术服务",
"AI人工智能", "VR/AR/MR", "翻译服务", "SaaS服务", "区块链", "企业后勤服务",
"企业办公服务", "文印广告", "法律服务", "工商财税", "学习培训", "源码交易",
"生产制造", "直播服务", "服装配饰设计", "摄影摄像服务", "数据服务",
]
async def _seed_task_categories(session: AsyncSession, now: str) -> None:
if await session.scalar(select(TaskCategory.id).limit(1)) is not None:
return
session.add_all([
TaskCategory(id=f"tc_{i:02d}", name=name, sort=i + 1, status="active")
for i, name in enumerate(_TASK_CATEGORY_NAMES)
])
await session.commit()
async def _seed_operator_business(session: AsyncSession, now: str) -> None:
if await session.scalar(select(Task.id).limit(1)) is not None:
return
session.add_all([
Task(id="task_001", task_code="TK-001-UI", title="电商小程序首页 UI 设计",
category="设计创意", category_id="tc_10", sub_category="UI设计",
description="为电商小程序设计首页 UI,含 5 个页面",
tags="UI,设计", mode="bid", budget_min=2000, budget_max=5000,
deadline="2026-09-01", delivery_days=7, headcount=3,
display_priority=10, published_at=now,
status="published", publisher_org_id="o_ent_001",
publisher_name="云南某某甲方企业", created_at=now, updated_at=now),
Task(id="task_002", task_code="TK-002-CT", title="品牌文案写作(月度)",
category="写作和内容", category_id="tc_13", sub_category="内容写作",
description="每月 8 篇品牌公众号文案", tags="文案,内容",
mode="assign", budget_min=3000, budget_max=6000,
deadline="2026-12-31", delivery_days=14, headcount=1,
display_priority=5, status="review", publisher_org_id="o_ent_001",
publisher_name="云南某某甲方企业", created_at=now, updated_at=now),
Task(id="task_003", task_code="TK-003-DEV", title="小程序前后端开发",
category="移动端开发", category_id="tc_02", sub_category="小程序开发",
description="点餐小程序全栈开发,3 期交付", tags="开发",
mode="bid", budget_min=30000, budget_max=60000,
deadline="2026-10-15", delivery_days=30, headcount=3,
display_priority=20, status="pending", publisher_org_id="o_ent_001",
publisher_name="云南某某甲方企业", created_at=now, updated_at=now),
Task(id="task_004", task_code="TK-004-GRAB", title="短视频剪辑(扫码即领·独占)",
category="音视频", category_id="tc_08", sub_category="视频剪辑",
description="为园区企业制作 3 条产品短视频,扫码即可接单,独占一人,2 周内交付。",
tags="短视频,剪辑", mode="grab", budget_min=1500, budget_max=3000,
deadline="2026-11-30", delivery_days=14, exclusive=True, headcount=1,
display_priority=30, published_at=now,
status="published", publisher_org_id="o_ent_001",
publisher_name="园区运营方", created_at=now, updated_at=now),
Task(id="task_005", task_code="TK-005-REC", title="农产品品牌 Logo 设计(推荐)",
category="平面设计", category_id="tc_01", sub_category="品牌设计",
description="为农产品品牌设计 Logo,推荐合适合伙人接单。",
tags="Logo,品牌设计", mode="recommend", budget_min=800, budget_max=2000,
deadline="2026-12-20", delivery_days=10, headcount=1,
display_priority=25, published_at=now,
status="published", publisher_org_id="o_ent_001",
publisher_name="园区运营方", created_at=now, updated_at=now),
])
session.add_all([
ServiceProvider(id="prov_001", name="云超财税服务所", category="财税服务",
org_id="o_pro_001", level="gold", rating=4.8, order_count=320,
status="active", contact="service@yuncao.example", created_at=now, updated_at=now),
ServiceProvider(id="prov_002", name="滇峰法律咨询", category="法律服务",
org_id=None, level="premium", rating=4.6, order_count=150,
status="active", contact="law@dianfeng.example", created_at=now, updated_at=now),
ServiceProvider(id="prov_003", name="云岭工商代办", category="工商服务",
org_id=None, level="certified", rating=4.3, order_count=88,
status="pending", contact="biz@yunling.example", created_at=now, updated_at=now),
])
session.add_all([
ContentItem(id="cont_001", type="policy", title="云南省一次性创业补贴政策",
summary="对首次创业且正常经营 1 年以上的 OPC 发放一次性创业补贴",
body="适用对象、申报条件、补贴标准、申报流程……", publisher_id="u_gov_prov",
status="published", created_at=now, updated_at=now),
ContentItem(id="cont_002", type="news", title="平台上线公告",
summary="云超服平台正式上线运营", body="欢迎入驻……", publisher_id="u_demo_01",
status="published", created_at=now, updated_at=now),
])
session.add_all([
SystemConfig(key="platform.fee.task", value="0.05", description="任务佣金费率(5%", updated_at=now),
SystemConfig(key="platform.fee.provider", value="0.15", description="服务商分成比例(15%", updated_at=now),
])
# ---------------------------------------------------------------------------
# OPC 超级个体业务演示数据(工作台聚合:档案/任务/财务/消息)
# ---------------------------------------------------------------------------
async def _seed_opc_business(session: AsyncSession, now: str) -> None:
"""OPC 个人工作台演示数据(按用户幂等)。"""
if await session.scalar(select(OpcProfile.user_id).limit(1)) is not None:
return
# 档案(信用评分)
session.add_all([
OpcProfile(user_id="u_opc_01", credit_score=88, created_at=now, updated_at=now),
OpcProfile(user_id="u_opc_02", credit_score=82, created_at=now, updated_at=now),
])
# 个人任务看板
session.add_all([
OpcTask(id="ot_001", user_id="u_opc_01", title="电商小程序首页 UI 设计",
status="in_progress", budget=4000, deadline="2026-08-20", progress=65,
created_at=now, updated_at=now),
OpcTask(id="ot_002", user_id="u_opc_01", title="品牌公众号月度文案",
status="urgent", budget=3000, deadline="2026-08-10", progress=30,
created_at=now, updated_at=now),
OpcTask(id="ot_003", user_id="u_opc_01", title="Logo 及 VI 视觉规范",
status="completed", budget=5000, deadline="2026-07-15", progress=100,
created_at=now, updated_at=now),
OpcTask(id="ot_004", user_id="u_opc_02", title="宣传视频剪辑",
status="in_progress", budget=2500, deadline="2026-08-28", progress=45,
created_at=now, updated_at=now),
])
# 财务流水(月度收入 + 少量支出)
session.add_all([
FinanceRecord(id="fin_001", user_id="u_opc_01", category="income", amount=3200,
date="2026-02-10", note="UI 设计项目款", created_at=now),
FinanceRecord(id="fin_002", user_id="u_opc_01", category="income", amount=4500,
date="2026-03-12", note="Logo 设计项目款", created_at=now),
FinanceRecord(id="fin_003", user_id="u_opc_01", category="income", amount=2800,
date="2026-04-08", note="文案代写项目款", created_at=now),
FinanceRecord(id="fin_004", user_id="u_opc_01", category="income", amount=5100,
date="2026-05-20", note="小程序 UI 项目款", created_at=now),
FinanceRecord(id="fin_005", user_id="u_opc_01", category="income", amount=3900,
date="2026-06-15", note="电商详情页设计", created_at=now),
FinanceRecord(id="fin_006", user_id="u_opc_01", category="income", amount=4600,
date="2026-07-18", note="H5 营销页设计", created_at=now),
FinanceRecord(id="fin_007", user_id="u_opc_01", category="expense", amount=600,
date="2026-07-02", note="素材版权购买", created_at=now),
])
# 站内消息
session.add_all([
Message(id="msg_001", user_id="u_opc_01", msg_type="policy",
title="政策匹配提醒", content="2 项新政策与您高度匹配,请及时查看申报",
read=False, created_at=now),
Message(id="msg_002", user_id="u_opc_01", msg_type="task",
title="任务状态更新", content="您参与的「电商小程序首页 UI 设计」进度已更新",
read=False, created_at=now),
Message(id="msg_003", user_id="u_opc_01", msg_type="service",
title="服务商回复", content="云超财税服务所已回复您的询价",
read=True, created_at=now),
Message(id="msg_004", user_id="u_opc_01", msg_type="agent",
title="智能体建议", content="您的月度收入较上月增长 18%",
read=True, created_at=now),
])
# ---------------------------------------------------------------------------
# 端口工作台聚合数据(企业/载体/服务商/政务)
# ---------------------------------------------------------------------------
_PORT_DASHBOARDS: dict[str, dict] = {
"enterprise": {
"stats": [
{"key": "postedTasks", "value": 56},
{"key": "activeTasks", "value": 12},
{"key": "completedTasks", "value": 38},
{"key": "totalSpent", "value": "¥32.0万"},
{"key": "matchedTalents", "value": 186},
{"key": "cooperationRate", "value": "92%"},
],
"list": [
{"title": "企业官网 UI 设计", "meta": "进行中 · ¥5000-8000 · 12 家投标", "status": "进行中"},
{"title": "小程序前端开发", "meta": "进行中 · ¥8000-15000 · 8 家投标", "status": "进行中"},
{"title": "农产品品牌 Logo 设计", "meta": "进行中 · ¥3000-5000 · 15 家投标", "status": "进行中"},
{"title": "商业计划书撰写", "meta": "进行中 · ¥2000-4000 · 6 家投标", "status": "进行中"},
],
},
"carrier": {
"stats": [
{"key": "residentOPCs", "value": 186},
{"key": "totalSpace", "value": "5000㎡"},
{"key": "usedSpace", "value": "4200㎡"},
{"key": "occupancyRate", "value": "84%"},
{"key": "serviceOrders", "value": 45},
{"key": "thisMonthNewOPC", "value": 12},
],
"list": [
{"title": "云创设计工作室", "meta": "入驻 · 电子信息方向 · 工位 12", "status": "已入驻"},
{"title": "滇峰数据科技", "meta": "入驻 · 软件服务方向 · 工位 8", "status": "已入驻"},
{"title": "云南新媒体中心", "meta": "待审批 · 内容创作方向 · 工位 6", "status": "待审批"},
{"title": "绿野农业电商", "meta": "入驻 · 电商方向 · 工位 10", "status": "已入驻"},
],
},
"provider": {
"stats": [
{"key": "activeServices", "value": 18},
{"key": "ongoingOrders", "value": 24},
{"key": "completedOrders", "value": 156},
{"key": "totalRevenue", "value": "¥52.6万"},
{"key": "thisMonthIncome", "value": "¥8.56万"},
{"key": "avgRating", "value": 4.7},
],
"list": [
{"title": "代理记账服务(月度)", "meta": "进行中 · 云南某某甲方企业 · ¥199/月", "status": "进行中"},
{"title": "公司注册代办", "meta": "待处理 · 个人创业者 · ¥599/次", "status": "待处理"},
{"title": "季度财务报表编制", "meta": "已完成 · 云创财税 · ¥2000-3000", "status": "已完成"},
{"title": "税务筹划咨询", "meta": "进行中 · 鼎信税务所 · ¥1999/次", "status": "进行中"},
],
},
"government": {
"stats": [
{"key": "totalOPC", "value": 45600},
{"key": "registeredCarriers", "value": 168},
{"key": "policiesPublished", "value": 245},
{"key": "policiesMatched", "value": 18200},
{"key": "tasksInRegion", "value": 12500},
{"key": "completionRate", "value": "78%"},
],
"list": [
{"region": "昆明市", "opcCount": 12500, "taskCount": 3200, "completionRate": "82%"},
{"region": "大理州", "opcCount": 6800, "taskCount": 1800, "completionRate": "76%"},
{"region": "曲靖市", "opcCount": 5200, "taskCount": 1500, "completionRate": "79%"},
{"region": "红河州", "opcCount": 4800, "taskCount": 1200, "completionRate": "74%"},
{"region": "玉溪市", "opcCount": 3500, "taskCount": 900, "completionRate": "81%"},
],
"chart": [
{"label": "1月", "value": 2400},
{"label": "2月", "value": 2800},
{"label": "3月", "value": 3100},
{"label": "4月", "value": 2900},
{"label": "5月", "value": 3450},
{"label": "6月", "value": 3820},
],
},
}
async def _seed_port_dashboards(session: AsyncSession, now: str) -> None:
"""按端口写入工作台 JSON 载荷(幂等:任一端口已存在则跳过)。"""
if await session.scalar(select(PortalDashboard.port).limit(1)) is not None:
return
session.add_all(
[
PortalDashboard(
port=port,
payload=json.dumps(payload, ensure_ascii=False),
updated_at=now,
)
for port, payload in _PORT_DASHBOARDS.items()
]
)
async def _seed_market(session: AsyncSession, now: str) -> None:
"""补充平台市场数据(任务广场/政策/服务商),幂等(以 task_mk_001 为标记)。"""
if await session.scalar(select(Task.id).where(Task.id == "task_mk_001").limit(1)) is not None:
return
session.add_all([
Task(id="task_mk_001", title="企业官网 UI 设计", category="设计创意", sub_category="UI设计",
description="为企业官网设计首页与 3 个内页 UI", mode="bid",
budget_min=5000, budget_max=8000, deadline="2026-09-10",
status="published", publisher_org_id="o_ent_001",
publisher_name="云南某某甲方企业", created_at=now, updated_at=now),
Task(id="task_mk_002", title="小程序前后端开发", category="技术开发", sub_category="小程序开发",
description="点餐小程序全栈开发,3 期交付", mode="bid",
budget_min=30000, budget_max=60000, deadline="2026-10-15",
status="published", publisher_org_id="o_ent_001",
publisher_name="云南某某甲方企业", created_at=now, updated_at=now),
Task(id="task_mk_003", title="农产品品牌 Logo 设计", category="设计创意", sub_category="Logo设计",
description="为农业合作社设计品牌 Logo", mode="grab",
budget_min=3000, budget_max=5000, deadline="2026-08-25",
status="published", publisher_org_id=None,
publisher_name="大理农业合作社", created_at=now, updated_at=now),
Task(id="task_mk_004", title="短视频剪辑与制作", category="音视频", sub_category="短视频",
description="文旅宣传短视频剪辑", mode="grab",
budget_min=1500, budget_max=3000, deadline="2026-08-20",
status="published", publisher_org_id=None,
publisher_name="文旅传媒", created_at=now, updated_at=now),
Task(id="task_mk_005", title="商业计划书撰写", category="策划/写作", sub_category="文案写作",
description="创业项目商业计划书", mode="designated",
budget_min=2000, budget_max=4000, deadline="2026-09-01",
status="published", publisher_org_id=None,
publisher_name="创业团队", created_at=now, updated_at=now),
])
session.add_all([
ContentItem(id="cont_pol_001", type="policy", title="昆明市创业担保贷款政策",
summary="对符合条件的创业主体提供担保贷款支持",
body="适用对象、额度、利率与申报流程……", publisher_id="u_gov_prov",
status="published", created_at=now, updated_at=now),
ContentItem(id="cont_pol_002", type="policy", title="小微企业税收优惠减免",
summary="符合条件的小微企业可享受税收减免",
body="适用范围、减免标准与办理方式……", publisher_id="u_gov_prov",
status="published", created_at=now, updated_at=now),
ContentItem(id="cont_pol_003", type="policy", title="云南省一次性创业补贴",
summary="首次创业且正常经营 1 年以上发放一次性补贴",
body="申报条件、补贴标准与流程……", publisher_id="u_gov_prov",
status="published", created_at=now, updated_at=now),
])
# ---------------------------------------------------------------------------
# 端口子页面演示数据(企业人才/载体OPC与服务/服务商订单与服务/政务OPC·政策·载体·数据)
# ---------------------------------------------------------------------------
_PORT_PAGES: dict[tuple[str, str], dict] = {
("enterprise", "talents"): {
"items": [
{"title": "张伟 · UI设计师", "meta": "5年经验 · Figma/PS · 认证OPC", "tag": "认证"},
{"title": "李娜 · 前端开发", "meta": "3年经验 · Vue/React · 认证OPC", "tag": "认证"},
{"title": "王强 · 文案策划", "meta": "4年经验 · 公众号/短视频文案", "tag": "独立"},
{"title": "赵敏 · 数据分析", "meta": "2年经验 · Python/SQL", "tag": "独立"},
{"title": "陈晨 · 电商运营", "meta": "3年经验 · 抖音/淘宝", "tag": "认证"},
{"title": "刘洋 · 空间设计", "meta": "6年经验 · 民宿/商业空间", "tag": "认证"},
],
},
("carrier", "opc"): {
"items": [
{"title": "云创设计工作室", "meta": "电子信息方向 · 工位12 · 2026-03 入驻", "tag": "已入驻"},
{"title": "滇峰数据科技", "meta": "软件服务方向 · 工位8 · 2026-04 入驻", "tag": "已入驻"},
{"title": "云南新媒体中心", "meta": "内容创作方向 · 工位6 · 待审批", "tag": "待审批"},
{"title": "绿野农业电商", "meta": "电商方向 · 工位10 · 2026-05 入驻", "tag": "已入驻"},
{"title": "云南文创工坊", "meta": "文化创意方向 · 工位4 · 申请中", "tag": "申请中"},
],
},
("carrier", "services"): {
"items": [
{"title": "园区创业培训", "meta": "创业辅导 · 月度课程 · 已完成", "tag": "已完成"},
{"title": "工商注册代办", "meta": "云超财税 · 本期 12 单", "tag": "合作中"},
{"title": "政策申报指导", "meta": "省市区三级补贴申报", "tag": "进行中"},
{"title": "法务顾问服务", "meta": "滇峰法律 · 入驻企业专享", "tag": "合作中"},
],
},
("provider", "orders"): {
"items": [
{"title": "代理记账服务(月度)", "meta": "云南某某甲方企业 · ¥199/月 · 2026-07 开始", "tag": "进行中"},
{"title": "公司注册代办", "meta": "个人创业者 · ¥599/次 · 待处理", "tag": "待处理"},
{"title": "季度财务报表编制", "meta": "云创财税 · ¥2000-3000 · 已完成", "tag": "已完成"},
{"title": "税务筹划咨询", "meta": "鼎信税务所 · ¥1999/次 · 进行中", "tag": "进行中"},
{"title": "年度汇算清缴", "meta": "云南某某甲方企业 · ¥1500 · 待处理", "tag": "待处理"},
],
},
("provider", "services"): {
"items": [
{"title": "代理记账服务", "meta": "财税服务 · ¥199/月起 · 在售", "tag": "在售"},
{"title": "税务筹划咨询", "meta": "财税服务 · ¥1999/次 · 在售", "tag": "在售"},
{"title": "企业年报填报", "meta": "工商服务 · ¥99/次 · 在售", "tag": "在售"},
{"title": "审计报告出具", "meta": "财税服务 · ¥3000/份 · 草稿", "tag": "草稿"},
],
},
("government", "opc"): {
"items": [
{"title": "张伟 · UI设计师", "meta": "盘龙区 · 认证OPC · 信用88", "tag": "认证"},
{"title": "李娜 · 前端开发", "meta": "五华区 · 认证OPC · 信用85", "tag": "认证"},
{"title": "王强 · 文案策划", "meta": "盘龙区 · 独立OPC · 信用80", "tag": "独立"},
{"title": "赵敏 · 数据分析", "meta": "麒麟区 · 独立OPC · 信用82", "tag": "独立"},
],
},
("government", "policies"): {
"items": [
{"title": "云南省一次性创业补贴政策", "meta": "省级 · 2026-06 发布 · 申报中", "tag": "已发布"},
{"title": "昆明市创业担保贷款政策", "meta": "市级 · 2026-05 发布 · 申报中", "tag": "已发布"},
{"title": "小微企业税收优惠减免", "meta": "省级 · 2026-04 发布 · 申报中", "tag": "已发布"},
{"title": "青年人才创业支持计划", "meta": "市级 · 起草中", "tag": "草稿"},
],
},
("government", "carriers"): {
"items": [
{"title": "滇池创业园", "meta": "五华区 · 工位500 · 入驻率84%", "tag": "正常"},
{"title": "云创空间孵化器", "meta": "盘龙区 · 工位300 · 入驻率76%", "tag": "正常"},
{"title": "曲靖高新园区", "meta": "麒麟区 · 工位400 · 入驻率68%", "tag": "正常"},
],
},
("government", "data"): {
"stats": [
{"key": "opcTotal", "value": 45600},
{"key": "taskTotal", "value": 12500},
{"key": "carrierTotal", "value": 168},
{"key": "policyTotal", "value": 245},
],
"chart": [
{"label": "1月", "value": 3200},
{"label": "2月", "value": 3600},
{"label": "3月", "value": 4100},
{"label": "4月", "value": 3900},
{"label": "5月", "value": 4500},
{"label": "6月", "value": 5200},
],
},
("investor", "projects"): {
"items": [
{"title": "云上数仓 SaaS 平台", "meta": "人工智能 · 天使轮 · 融资 300万 · 估值 2000万", "tag": "天使轮"},
{"title": "滇南文旅数字营销", "meta": "文旅创意 · A轮 · 融资 800万 · 估值 6000万", "tag": "A轮"},
{"title": "生物医药检测服务", "meta": "生物医药 · 种子轮 · 融资 150万", "tag": "种子轮"},
{"title": "智慧农业物联", "meta": "农业科技 · 天使轮 · 融资 200万 · 估值 1500万", "tag": "天使轮"},
{"title": "本地生活 AI 助手", "meta": "人工智能 · 种子轮 · 融资 100万", "tag": "种子轮"},
],
},
("investor", "trainings"): {
"items": [
{"title": "商业计划书(BP)撰写实战", "meta": "投融资基础 · 视频课 · 免费", "tag": "免费"},
{"title": "创业公司估值与投资条款", "meta": "投融资进阶 · 视频课 · 付费", "tag": "付费"},
{"title": "尽职调查实务(投资人视角)", "meta": "投融资进阶 · 直播课 · 报名中", "tag": "报名中"},
{"title": "路演技巧与打动投资人", "meta": "融资准备 · 视频课 · 免费", "tag": "免费"},
{"title": "股权结构与法律合规", "meta": "融资准备 · 视频课 · 付费", "tag": "付费"},
],
},
("investor", "portfolio"): {
"stats": [
{"key": "totalInvested", "value": "¥500万"},
{"key": "portfolioCount", "value": 6},
{"key": "activeIntents", "value": 3},
{"key": "roadshowAttended", "value": 12},
],
"items": [
{"title": "云上数仓 SaaS", "meta": "已投 · 天使轮 · 当前估值 2000万", "tag": "已投"},
{"title": "滇南文旅", "meta": "已投 · A轮 · 当前估值 6000万", "tag": "已投"},
{"title": "本地生活 AI 助手", "meta": "跟踪中 · 种子轮", "tag": "跟踪中"},
],
},
("opc", "tax"): {
"items": [
{"title": "个人所得税 · 7月申报", "meta": "申报期至 2026-08-15 · 待申报", "tag": "待申报"},
{"title": "增值税 · 7月申报", "meta": "申报期至 2026-08-15 · 待申报", "tag": "待申报"},
{"title": "企业所得税 · 二季度", "meta": "已于 2026-07-20 申报", "tag": "已申报"},
],
},
("opc", "affairs"): {
"items": [
{"title": "个体工商户注册", "meta": "工商办理 · 材料已提交 · 办理中", "tag": "办理中"},
{"title": "年报公示", "meta": "工商办理 · 已完成", "tag": "已完成"},
{"title": "一次性创业补贴申报", "meta": "政务申报 · 区县初审中", "tag": "初审中"},
],
},
("developer", "dashboard"): {
"stats": [
{"key": "appCount", "value": 3},
{"key": "pluginCount", "value": 5},
{"key": "skillCount", "value": 8},
{"key": "apiCalls", "value": "12.6万"},
],
},
("developer", "apps"): {
"items": [
{"title": "云上订单助手", "meta": "应用 · 已上架 · 调用 3.2万次", "tag": "已上架"},
{"title": "创业政策查询", "meta": "应用 · 已上架 · 调用 5.1万次", "tag": "已上架"},
{"title": "财税自动记账", "meta": "应用 · 待审核", "tag": "待审核"},
],
},
("developer", "plugins"): {
"items": [
{"title": "task-helper", "meta": "插件 · 版本 v1.2 · 已上架", "tag": "已上架"},
{"title": "policy-mcp", "meta": "插件 · MCP · 已上架", "tag": "已上架"},
{"title": "invoice-extract", "meta": "插件 · 开发中", "tag": "开发中"},
],
},
("developer", "skills"): {
"items": [
{"title": "BP 撰写助手", "meta": "技能 · 已上架 · 使用 1200次", "tag": "已上架"},
{"title": "财税问答", "meta": "技能 · 已上架 · 使用 860次", "tag": "已上架"},
{"title": "路演 PPT 生成", "meta": "技能 · 待审核", "tag": "待审核"},
],
},
}
async def _seed_port_pages(session: AsyncSession, now: str) -> None:
"""写入端口子页面演示数据(幂等:任一 (port,page) 已存在则跳过)。"""
if await session.scalar(select(PortalPage.port).limit(1)) is not None:
return
session.add_all(
[
PortalPage(
port=port, page=page,
payload=json.dumps(payload, ensure_ascii=False),
updated_at=now,
)
for (port, page), payload in _PORT_PAGES.items()
]
)
async def _seed_investor(session: AsyncSession, now: str) -> None:
"""投资人端演示数据(偏好/路演/意向),幂等(以偏好为标记)。"""
if await session.scalar(select(InvestorPreference.user_id).limit(1)) is not None:
return
session.add_all([
InvestorPreference(
user_id="u_inv_01",
industries='["人工智能","文旅","农业科技"]',
stage="angel", amount_min=50, amount_max=300, region_id="r_prov_yn",
updated_at=now,
),
InvestorPreference(
user_id="u_inv_02",
industries='["人工智能","生物医药","智能制造"]',
stage="series_a", amount_min=500, amount_max=3000, region_id="r_prov_yn",
updated_at=now,
),
])
session.add_all([
Roadshow(
id="rs_001", publisher_id="u_inv_02", publisher_role="investor",
title="云南 AI 创业项目专场路演", summary="8 个 AI 方向创业项目线上路演",
activity_type="online", scope_type="all", region_id=None,
start_at="2026-08-20T14:00:00", end_at="2026-08-20T17:00:00",
register_deadline="2026-08-18", quota=100, live_url="",
status="published", need_review=True, created_at=now, updated_at=now,
),
Roadshow(
id="rs_002", publisher_id="u_gov_prov", publisher_role="government",
title="省级创业投融资对接会", summary="省级载体与投资人对接",
activity_type="hybrid", scope_type="region", region_id="r_prov_yn",
start_at="2026-08-28T09:00:00", end_at="2026-08-28T12:00:00",
register_deadline="2026-08-25", quota=200, venue="昆明国际会展中心",
status="published", need_review=False, created_at=now, updated_at=now,
),
])
session.add_all([
InvestmentIntent(
id="intent_001", investor_id="u_inv_01", project_id="proj_001",
project_name="云上数仓 SaaS 平台", status="contacted",
message="对贵项目感兴趣,希望约谈", created_at=now, updated_at=now,
),
])
async def _sync_permissions(session: AsyncSession, now: str) -> None:
"""幂等补种权限与角色权限映射(供既有库使用)。
只插入缺失的 Permission 行与缺失的 RolePermission 链接,不删除已有
自定义授权,避免覆盖运营端后续经「角色权限配置」做的调整。
"""
for pid, name, category, module in PERMISSIONS:
if await session.get(Permission, pid) is None:
session.add(Permission(id=pid, name=name, category=category, module=module))
for role_id, perms in ROLE_PERMISSIONS.items():
if await session.get(Role, role_id) is None:
continue
existing = {
rp.permission_id
for rp in await session.scalars(
select(RolePermission).where(RolePermission.role_id == role_id)
)
}
for perm in perms:
if perm not in existing:
session.add(RolePermission(role_id=role_id, permission_id=perm))
async def _ensure_extra_demo_users(session: AsyncSession, now: str) -> None:
"""补建新增的演示用户(投资人等),供既有库使用(幂等)。"""
EXTRA = [
("u_inv_01", "inv01", "投资人账号", "investor", "personal", None, "r_prov_yn"),
("u_inv_02", "inv02", "机构投资人", "investor", "org_director", None, "r_prov_yn"),
# 运营端内部子角色演示账号
("u_op_admin", "op_admin", "运营管理员", "operator", "op_admin", None, "r_prov_yn"),
("u_op_cs", "op_cs", "运营客服", "operator", "op_customer_service", None, "r_prov_yn"),
("u_op_fin", "op_fin", "运营财务", "operator", "op_finance", None, "r_prov_yn"),
("u_op_tech", "op_tech", "运营运维", "operator", "op_techops", None, "r_prov_yn"),
# 机构子账号(企业财务/任务发布、服务商执行/财务)
("u_ent_fin", "ent_fin", "企业财务", "enterprise", "operator", "o_ent_001", "r_dist_pl"),
("u_ent_pub", "ent_pub", "企业任务发布", "enterprise", "operator", "o_ent_001", "r_dist_pl"),
("u_pro_exec", "pro_exec", "服务商执行", "provider", "operator", "o_pro_001", "r_city_km"),
("u_pro_fin", "pro_fin", "服务商财务", "provider", "operator", "o_pro_001", "r_city_km"),
# 开放平台开发者
("u_dev_01", "dev01", "个人开发者", "developer", "dev_individual", None, "r_prov_yn"),
("u_dev_02", "dev02", "机构开发者", "developer", "dev_org_admin", None, "r_prov_yn"),
]
for (uid, username, nickname, role, sub_role, org_id, region_id) in EXTRA:
if await session.get(User, uid) is not None:
continue
digest, salt = hash_password("123456")
session.add(
User(
id=uid, username=username, nickname=nickname,
password_hash=digest, password_salt=salt,
role=role, sub_role=sub_role, org_id=org_id, region_id=region_id,
status="active", token_version=0, created_at=now, updated_at=now,
source="seed", auth_type="admin",
)
)
for seed in AGENT_SEED:
await _add_agent(session, seed, uid, None, now)
async def _seed_ecosystem(session: AsyncSession, now: str) -> None:
"""生态横切演示数据(通知/补贴/引荐/培训),幂等。"""
if await session.scalar(select(Notification.id).limit(1)) is None:
session.add_all([
Notification(id="ntf_001", user_id="u_opc_01", type="task",
title="任务进度更新", content="您的任务「电商小程序首页 UI 设计」进度已更新",
read=False, created_at=now),
Notification(id="ntf_002", user_id="u_opc_01", type="policy",
title="新政策匹配", content="2 项新政策与您高度匹配", read=False, created_at=now),
Notification(id="ntf_003", user_id="u_ent_01", type="task",
title="收到投标", content="您的任务收到新的竞标", read=False, created_at=now),
])
if await session.scalar(select(SubsidyApplication.id).limit(1)) is not None:
return
session.add_all([
SubsidyApplication(id="sub_001", opc_id="u_opc_01", opc_name="OPC个人创业者",
title="云南省一次性创业补贴", amount=10000, region_id="r_dist_wh",
status="applying", created_at=now, updated_at=now),
SubsidyApplication(id="sub_002", opc_id="u_opc_02", opc_name="OPC个体工商户",
title="昆明市创业担保贷款贴息", amount=5000, region_id="r_dist_pl",
status="district_review", created_at=now, updated_at=now),
SubsidyApplication(id="sub_003", opc_id="u_opc_01", opc_name="OPC个人创业者",
title="青年人才创业支持计划", amount=20000, region_id="r_dist_wh",
status="city_review", created_at=now, updated_at=now),
])
session.add_all([
ServiceReferral(id="ref_001", carrier_id="o_car_001", provider_id="o_pro_001",
provider_name="云超财税服务所", opc_id="u_opc_01", opc_name="OPC个人创业者",
status="referred", created_at=now, updated_at=now),
])
session.add_all([
TrainingEnrollment(id="treg_001", user_id="u_inv_01", training_id="商业计划书(BP)撰写实战",
training_name="商业计划书(BP)撰写实战", status="enrolled", created_at=now),
])
async def _seed_org_members(session: AsyncSession, now: str) -> None:
"""机构成员(机构主账号 + 子账号),幂等(以 organization_members 为标记)。"""
await session.flush()
if await session.scalar(select(OrganizationMember.org_id).limit(1)) is not None:
return
# 每个机构默认一个管理员主账号
members = [
("o_ent_001", "u_ent_01", "admin", True),
("o_car_001", "u_car_01", "admin", True),
("o_pro_001", "u_pro_01", "admin", True),
# 企业子账号(财务/任务发布)
("o_ent_001", "u_ent_fin", "finance", False),
("o_ent_001", "u_ent_pub", "publisher", False),
# 服务商子账号(服务执行/财务)
("o_pro_001", "u_pro_exec", "service_executor", False),
("o_pro_001", "u_pro_fin", "finance", False),
]
for org_id, user_id, role, is_admin in members:
session.add(OrganizationMember(org_id=org_id, user_id=user_id, role=role,
is_admin=is_admin, status="active", joined_at=now))