4dedb43d7f
数据模型: - 新增 tenant_discounts(运营端载体折扣) - 新增 tenant_user_discounts(载体端账号折扣) - 新增 compute_recharges(算力充值记录) - 新增 compute_balance_allocations(余额分配记录) - 新增 compute_usage_records(算力使用记录) - 扩展 park_tenants(default_company_discount, default_user_discount) - 扩展 park_companies(compute_balance, compute_balance_used) - 扩展 company_members(role, compute_balance, compute_balance_used, left_at, left_reason) 核心服务: - compute_pricing_service.py:四级折扣价格计算、余额扣费、企业余额管理 API接口(/api/compute): - 运营端:载体折扣管理、标准价管理 - 载体端:企业折扣设置、账号折扣设置、默认折扣设置 - 企业端:余额充值、成员余额分配/回收、充值/分配记录 - 个人端:我的余额、使用记录、退出企业 - 内部:价格查询、算力扣费 数据库迁移:0064_compute_discount_balance.py
977 lines
52 KiB
Python
977 lines
52 KiB
Python
# -*- 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,
|
||
MarketCategory,
|
||
Message,
|
||
Notification,
|
||
OpcProfile,
|
||
Organization,
|
||
OrganizationMember,
|
||
ParkMember,
|
||
ParkTenant,
|
||
Permission,
|
||
PortalDashboard,
|
||
PortalPage,
|
||
Region,
|
||
Roadshow,
|
||
RoadshowRegistration,
|
||
Role,
|
||
RolePermission,
|
||
ServiceProvider,
|
||
ServiceReferral,
|
||
SessionToken,
|
||
SubsidyApplication,
|
||
SystemConfig,
|
||
Task,
|
||
TaskCategory,
|
||
TrainingEnrollment,
|
||
User,
|
||
)
|
||
from .repositories import new_id, utcnow_iso
|
||
from .security import hash_password
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# 角色
|
||
# ---------------------------------------------------------------------------
|
||
# 角色定义:仅保留 OPC基础(opc_member)、园区(carrier)、运营(operator) 三端
|
||
# 已移除:enterprise / provider / government / investor / developer
|
||
# ---------------------------------------------------------------------------
|
||
ROLES = [
|
||
# 业务角色
|
||
("opc_member", "OPC超级个体", "business"),
|
||
("carrier", "创业载体(园区)", "business"),
|
||
("operator", "平台运营方", "business"),
|
||
# 运营方内部子角色
|
||
("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 端口内子角色
|
||
("carrier|admin", "园区管理员", "business"),
|
||
("carrier|operator", "园区操作者", "business"),
|
||
("opc_member|certified", "认证OPC", "business"),
|
||
("opc_member|independent", "独立OPC", "business"),
|
||
]
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# 权限
|
||
# ---------------------------------------------------------------------------
|
||
PERMISSIONS = [
|
||
# 各门户菜单(仅保留 opc/carrier/operator)
|
||
("menu:opc_dashboard", "OPC 门户", "menu", "opc"),
|
||
("menu:carrier_dashboard", "载体门户", "menu", "carrier"),
|
||
("menu:operator_dashboard", "运营门户", "menu", "operator"),
|
||
# 管理菜单
|
||
("menu:admin_user_mgmt", "用户管理", "menu", "admin"),
|
||
("menu:admin_role_mgmt", "角色权限管理", "menu", "admin"),
|
||
("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_market", "市场管理", "menu", "admin"),
|
||
("menu:admin_config", "系统配置", "menu", "admin"),
|
||
("menu:admin_desktop_updates", "桌面端版本管理", "menu", "admin"),
|
||
("menu:admin_agents", "智能体管理", "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"),
|
||
# 企业管理能力(OPC 叠加,非身份):company_members.is_admin 即可调用 /admin/ent/*,
|
||
# 不绑权限码角色(企业管理员不是身份)。
|
||
]
|
||
|
||
# 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",
|
||
],
|
||
"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_agents",
|
||
"menu:admin_market",
|
||
"menu:admin_desktop_updates",
|
||
"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",
|
||
],
|
||
"carrier|admin": ["menu:carrier_dashboard", "action:org.manage"],
|
||
"carrier|operator": ["menu:carrier_dashboard"],
|
||
"opc_member|certified": ["menu:opc_dashboard"],
|
||
"opc_member|independent": ["menu:opc_dashboard"],
|
||
}
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# 区域(省/市/区县 示例树)
|
||
# ---------------------------------------------------------------------------
|
||
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_car_01", "car01", "园区运营账号", "123456", "carrier", None, "o_car_001", "r_dist_wh"),
|
||
("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"),
|
||
]
|
||
|
||
|
||
# 系统配置默认值(平台费率 + 短信生态)。幂等补种:仅插入缺失键,不覆盖已有值。
|
||
_DEFAULT_SYSTEM_CONFIGS: list[tuple[str, str, str]] = [
|
||
("platform.fee.task", "0.05", "任务佣金费率(5%)"),
|
||
("platform.fee.provider", "0.15", "服务商分成比例(15%)"),
|
||
# ── 短信生态配置(admin「系统配置 → 短信生态」在线维护) ──────────────
|
||
("sms.provider", "stub", "短信 provider(stub|aliyun)"),
|
||
("sms.aliyun",
|
||
'{"access_key_id":"","access_key_secret":"","sign_name":"","region_id":"cn-hangzhou","endpoint":"dysmsapi.aliyuncs.com"}',
|
||
"阿里云短信总配置(密钥/签名/区域)"),
|
||
("sms.template.login", '{"template_id":"","variables":["code","minute"]}',
|
||
"登录验证码模板(变量:code 验证码, minute 有效分钟)"),
|
||
("sms.template.register", '{"template_id":"","variables":["code","minute"]}',
|
||
"注册验证码模板(变量:code 验证码, minute 有效分钟)"),
|
||
("sms.template.notification", '{"template_id":"","variables":[]}',
|
||
"通知提醒模板(变量按业务定义,如审核结果等)"),
|
||
("sms.template.order_status", '{"template_id":"","variables":["order_no","status"]}',
|
||
"订单状态变动模板(变量:order_no 订单号, status 状态)"),
|
||
("sms.template.appointment", '{"template_id":"","variables":["service_name","schedule_at","contact"]}',
|
||
"服务预约模板(变量:service_name 服务名, schedule_at 预约时间, contact 联系方式)"),
|
||
]
|
||
|
||
|
||
async def _seed_system_configs(session: AsyncSession, now: str) -> None:
|
||
"""幂等补齐系统配置:已存在的键不覆盖,仅插入缺失项。"""
|
||
for key, value, description in _DEFAULT_SYSTEM_CONFIGS:
|
||
exists = await session.get(SystemConfig, key)
|
||
if exists is None:
|
||
session.add(SystemConfig(key=key, value=value, description=description,
|
||
updated_at=now))
|
||
|
||
|
||
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_market_categories(session, now)
|
||
await _seed_port_pages(session, now)
|
||
await _seed_org_members(session, now)
|
||
await _seed_carrier_park_binding(session, now)
|
||
await _seed_system_configs(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",
|
||
)
|
||
)
|
||
|
||
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_market_categories(session, now)
|
||
await _seed_port_pages(session, now)
|
||
await _seed_org_members(session, now)
|
||
await _seed_carrier_park_binding(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_demo_01",
|
||
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),
|
||
])
|
||
await _seed_system_configs(session, 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([
|
||
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_demo_01",
|
||
status="published", created_at=now, updated_at=now),
|
||
ContentItem(id="cont_pol_002", type="policy", title="小微企业税收优惠减免",
|
||
summary="符合条件的小微企业可享受税收减免",
|
||
body="适用范围、减免标准与办理方式……", publisher_id="u_demo_01",
|
||
status="published", created_at=now, updated_at=now),
|
||
ContentItem(id="cont_pol_003", type="policy", title="云南省一次性创业补贴",
|
||
summary="首次创业且正常经营 1 年以上发放一次性补贴",
|
||
body="申报条件、补贴标准与流程……", publisher_id="u_demo_01",
|
||
status="published", created_at=now, updated_at=now),
|
||
])
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# 市场分类(skill/plugin/app 各类型独立,admin 端弹窗在线维护)
|
||
# ---------------------------------------------------------------------------
|
||
async def _seed_market_categories(session: AsyncSession, now: str) -> None:
|
||
"""幂等补种市场分类字典(空表才写;此后由 admin 端维护)。"""
|
||
from ..market.categories import ensure_default_categories
|
||
await ensure_default_categories(session, 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_demo_01", 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_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"),
|
||
]
|
||
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",
|
||
)
|
||
)
|
||
|
||
|
||
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_carrier_park_binding(session: AsyncSession, now: str) -> None:
|
||
"""载体账号绑定默认园区(T001),保证载体端任务管理开箱可用(幂等)。
|
||
|
||
默认园区由园区子应用 ensure_default_tenant 创建;此处兜底确保存在并绑定
|
||
种子载体账号 u_car_01,载体端任务管理/大屏按园区归属解析依赖该绑定。
|
||
"""
|
||
from sqlalchemy import select as _select
|
||
tid = "T001"
|
||
if await session.get(ParkTenant, tid) is None:
|
||
session.add(ParkTenant(
|
||
id=tid, name="昆明市大学生创业园", username="admin", status="active",
|
||
intro_json="[]", data_json="{}", agent_json="{}",
|
||
created_at=now,
|
||
))
|
||
await session.flush()
|
||
for uid in ("u_car_01",):
|
||
row = await session.scalar(
|
||
_select(ParkMember).where(ParkMember.user_id == uid, ParkMember.park_id == tid))
|
||
if row is None:
|
||
session.add(ParkMember(
|
||
id=new_id("pm"), user_id=uid, park_id=tid, member_type="admin",
|
||
status="active", created_by="seed", 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
|
||
# 每个机构默认一个管理员主账号(仅保留园区 carrier)
|
||
members = [
|
||
("o_car_001", "u_car_01", "admin", True),
|
||
]
|
||
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))
|