Files
server-core/app/infrastructure/models.py
T
Pine dbc29eee59 feat(membership): 成员制归属重构与叠加制身份(多对多成员表+转园两级审核)
- park_members/company_members 多对多成员表(0028),users.affiliation 为派生缓存由 sync_user_affiliation 刷新
- 转园两级审核状态机(0029):pending_from→pending_to→approved,支持用户/企业整体转园与运营端兜底
- 叠加制身份(0030):身份恒为运营/载体/OPC,企业管理员为能力叠加非身份,去除 enterprise/carrier 直写角色
- rbac 新增 memberships/park-transfers/企业管理员工作台 /admin/ent/* 接口

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-31 20:36:26 +08:00

1079 lines
58 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 -*-
"""SQLAlchemy ORM 模型(auth/RBAC 域)+ Pydantic 请求/响应模型。
- ORM 模型对应 SQLite 各表(users/roles/permissions/organizations/regions/
sessions/audit_logs/agents)。
- Pydantic 模型与 PineAgents 主后端 ``src/pineagents/app/routers/auth.py``
中的请求/响应模型一一对应,转发层透传时不会丢字段。
"""
from __future__ import annotations
from pydantic import BaseModel, Field
from sqlalchemy import (
Boolean,
Float,
ForeignKey,
Integer,
PrimaryKeyConstraint,
String,
Text,
UniqueConstraint,
)
from sqlalchemy.orm import Mapped, mapped_column
from .db import Base
# ===========================================================================
# SQLAlchemy ORM 模型
# ===========================================================================
class User(Base):
__tablename__ = "users"
__table_args__ = {"sqlite_autoincrement": True}
id: Mapped[str] = mapped_column(String, primary_key=True)
username: Mapped[str] = mapped_column(String, unique=True, nullable=False)
password_hash: Mapped[str] = mapped_column(String, nullable=False)
password_salt: Mapped[str] = mapped_column(String, nullable=False)
# 统一登录:微信 openid(登录即建 opc_member 身份);phone 与 username(手机号)对齐
wx_openid: Mapped[str] = mapped_column(String, default="", index=True) # 公众号/网页开放平台
wx_unionid: Mapped[str] = mapped_column(String, default="", index=True) # 微信 unionid(跨应用统一)
wx_mini_openid: Mapped[str] = mapped_column(String, default="", index=True) # 小程序 openid(与网页不同)
phone: Mapped[str] = mapped_column(String, default="")
email: Mapped[str] = mapped_column(String, default="")
nickname: Mapped[str] = mapped_column(String, default="")
account: Mapped[str] = mapped_column(String, default="")
company: Mapped[str] = mapped_column(String, default="")
room: Mapped[str] = mapped_column(String, default="")
avatar: Mapped[str] = mapped_column(String, default="")
company_avatar: Mapped[str] = mapped_column(String, default="")
gender: Mapped[str] = mapped_column(String, default="") # male|female|unknown
birthday: Mapped[str] = mapped_column(String, default="") # YYYY-MM-DD
# 用户详细资料(参考入园申请表 §一 申请人信息)
id_card: Mapped[str] = mapped_column(String, default="") # 身份证号
ethnicity: Mapped[str] = mapped_column(String, default="") # 民族
grad_school_major: Mapped[str] = mapped_column(String, default="") # 毕业院校及专业
grad_time: Mapped[str] = mapped_column(String, default="") # 毕业时间
# RBAC
role: Mapped[str] = mapped_column(String, default="opc_member") # 业务角色
sub_role: Mapped[str] = mapped_column(String, nullable=True) # 政务级/运营方内部
org_id: Mapped[str | None] = mapped_column(ForeignKey("organizations.id"), nullable=True)
region_id: Mapped[str | None] = mapped_column(ForeignKey("regions.id"), nullable=True)
status: Mapped[str] = mapped_column(String, default="active") # active | disabled
token_version: Mapped[int] = mapped_column(Integer, default=0) # revoke-all 递增
# ── 来源与登录跟踪(全局用户统一,记录准确来源) ──
source: Mapped[str] = mapped_column(String, default="") # mini_program|web|desktop|park|admin|seed|wx|phone|unknown
auth_type: Mapped[str] = mapped_column(String, default="") # password|phone|wx_openid|admin
register_ip: Mapped[str] = mapped_column(String, default="")
last_login_ip: Mapped[str] = mapped_column(String, default="")
last_login_at: Mapped[str] = mapped_column(String, default="")
# ── 算力(引擎用户镜像,全局一致) ──
compute_provisioned: Mapped[bool] = mapped_column(Boolean, default=False) # 是否已在算力引擎建号
compute_username: Mapped[str] = mapped_column(String, default="") # 引擎用户名(= username)
compute_quota: Mapped[int] = mapped_column(Integer, default=0) # 缓存引擎可用额度
compute_used_quota: Mapped[int] = mapped_column(Integer, default=0) # 缓存引擎已用额度
# ── 状态与身份分类 ──
certification_status: Mapped[str] = mapped_column(String, default="uncertified") # uncertified|pending|certified|rejected
certification_time: Mapped[str] = mapped_column(String, default="")
affiliation: Mapped[str] = mapped_column(String, default="independent") # independent:独立OPC | park:所属园区
park_id: Mapped[str] = mapped_column(String, default="") # 所属园区(id)
park_name: Mapped[str] = mapped_column(String, default="") # 所属园区(名)
park_company_id: Mapped[str | None] = mapped_column(String, nullable=True) # 所属园区企业(id),成员归属一家企业
account_type: Mapped[str] = mapped_column(String, default="opc_default") # opc_default|park_staff|platform_staff|provider|enterprise
# 小程序/网页「报名资料」字段(现状标签 + 关注主题 JSON)
opc_status: Mapped[str] = mapped_column(String, default="")
topics: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class Role(Base):
__tablename__ = "roles"
id: Mapped[str] = mapped_column(String, primary_key=True) # 角色码
name: Mapped[str] = mapped_column(String, nullable=False) # 展示名
scope_type: Mapped[str] = mapped_column(String, default="business") # business|operator-internal|government-level
description: Mapped[str] = mapped_column(String, default="")
class Permission(Base):
__tablename__ = "permissions"
id: Mapped[str] = mapped_column(String, primary_key=True) # 权限码 menu:xx / action:xx
name: Mapped[str] = mapped_column(String, nullable=False)
category: Mapped[str] = mapped_column(String, default="action") # menu | action
module: Mapped[str] = mapped_column(String, default="") # admin|government|...
description: Mapped[str] = mapped_column(String, default="")
class RolePermission(Base):
__tablename__ = "role_permissions"
role_id: Mapped[str] = mapped_column(
ForeignKey("roles.id", ondelete="CASCADE"), primary_key=True,
)
permission_id: Mapped[str] = mapped_column(
ForeignKey("permissions.id", ondelete="CASCADE"), primary_key=True,
)
class Organization(Base):
__tablename__ = "organizations"
id: Mapped[str] = mapped_column(String, primary_key=True)
name: Mapped[str] = mapped_column(String, nullable=False)
type: Mapped[str] = mapped_column(String, default="enterprise") # enterprise|carrier|provider
region_id: Mapped[str | None] = mapped_column(ForeignKey("regions.id"), nullable=True)
parent_id: Mapped[str | None] = mapped_column(ForeignKey("organizations.id"), nullable=True)
status: Mapped[str] = mapped_column(String, default="active")
created_at: Mapped[str] = mapped_column(String, default="")
class OrganizationMember(Base):
"""机构成员(机构主账号 + 机构内子账号):一个账号可挂多个机构。"""
__tablename__ = "organization_members"
org_id: Mapped[str] = mapped_column(
ForeignKey("organizations.id", ondelete="CASCADE"), primary_key=True,
)
user_id: Mapped[str] = mapped_column(
ForeignKey("users.id", ondelete="CASCADE"), primary_key=True,
)
role: Mapped[str] = mapped_column(String, default="member") # admin/finance/publisher/service_executor/service_deliverer/clerk/...
is_admin: Mapped[bool] = mapped_column(Boolean, default=False) # 机构主账号/管理员
status: Mapped[str] = mapped_column(String, default="active")
joined_at: Mapped[str] = mapped_column(String, default="")
class Region(Base):
__tablename__ = "regions"
id: Mapped[str] = mapped_column(String, primary_key=True)
name: Mapped[str] = mapped_column(String, nullable=False)
level: Mapped[str] = mapped_column(String, default="district") # province|city|district
parent_id: Mapped[str | None] = mapped_column(ForeignKey("regions.id"), nullable=True)
created_at: Mapped[str] = mapped_column(String, default="")
class SessionToken(Base):
__tablename__ = "sessions"
id: Mapped[str] = mapped_column(String, primary_key=True)
jti: Mapped[str] = mapped_column(String, unique=True, nullable=False)
token: Mapped[str] = mapped_column(String, default="") # 完整 JWT(调试用)
user_id: Mapped[str] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
username: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")
expires_at: Mapped[str] = mapped_column(String, default="")
revoked: Mapped[bool] = mapped_column(Boolean, default=False)
class AuditLog(Base):
__tablename__ = "audit_logs"
id: Mapped[str] = mapped_column(String, primary_key=True)
user_id: Mapped[str | None] = mapped_column(ForeignKey("users.id"), nullable=True)
action: Mapped[str] = mapped_column(String, default="") # login|role.assign|data.view|...
resource: Mapped[str] = mapped_column(String, default="") # user|role|enterprise|region|...
resource_id: Mapped[str] = mapped_column(String, default="")
detail: Mapped[str] = mapped_column(Text, default="")
ip: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")
class Agent(Base):
__tablename__ = "agents"
# id + user_id + port 复合主键:每个用户在每个端口持有独立的默认/QA 智能体(多端口彻底隔离)
__table_args__ = (PrimaryKeyConstraint("id", "user_id", "port"),)
id: Mapped[str] = mapped_column(String)
user_id: Mapped[str] = mapped_column(
ForeignKey("users.id", ondelete="CASCADE"), nullable=False,
)
port: Mapped[str] = mapped_column(String, default="opc") # opc/operator/government/... 端口隔离
name: Mapped[str] = mapped_column(String, default="")
description: Mapped[str] = mapped_column(Text, default="")
language: Mapped[str] = mapped_column(String, default="zh")
model_name: Mapped[str] = mapped_column(String, default="")
deletable: Mapped[bool] = mapped_column(Boolean, default=True)
use_fixed_soul: Mapped[bool] = mapped_column(Boolean, default=False)
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
# ── 运营端业务模型(平台运营/任务/服务商/内容/配置)────────────────────────
class Task(Base):
"""平台任务(运营端可审核/下架;后续各端口接入)。
状态机(扩展支持扫码接单):draft/pending/review/published/claimed/doing/completed/cancelled。
扫码接单流转:published → claimed(claimed_by/claimed_at) → doing(doing_at) → completed。
历史接单流水见 TaskClaimclaim 记录 claimed_by/claimed_at/doing_at。
"""
__tablename__ = "tasks"
id: Mapped[str] = mapped_column(String, primary_key=True)
task_code: Mapped[str] = mapped_column(String, default="", index=True) # 展示/扫码短码(唯一)
title: Mapped[str] = mapped_column(String, default="")
category: Mapped[str] = mapped_column(String, default="") # 分类字典 name(见 TaskCategory
category_id: Mapped[str | None] = mapped_column(ForeignKey("task_categories.id"), nullable=True)
sub_category: Mapped[str] = mapped_column(String, default="")
description: Mapped[str] = mapped_column(Text, default="")
tags: Mapped[str] = mapped_column(String, default="") # 逗号分隔展示标签
mode: Mapped[str] = mapped_column(String, default="grab") # grab/bid/assign/recommend(旧 designated→assign/dispatch→recommend)
budget_min: Mapped[int] = mapped_column(Integer, default=0)
budget_max: Mapped[int] = mapped_column(Integer, default=0)
deadline: Mapped[str] = mapped_column(String, default="") # 报名/接单截止时间
delivery_days: Mapped[int] = mapped_column(Integer, default=0) # 交付时限(接单后 N 天)
headcount: Mapped[int] = mapped_column(Integer, default=0) # 限制接单人数(0=不限)
exclusive: Mapped[bool] = mapped_column(Boolean, default=False) # 是否独占(仅一人可接)
display_priority: Mapped[int] = mapped_column(Integer, default=0) # 大屏展示排序(越大越前)
status: Mapped[str] = mapped_column(String, default="draft") # draft/pending/review/published/claimed/doing/completed/cancelled
published_at: Mapped[str] = mapped_column(String, default="") # 发布时间(→published 时)
claimed_by: Mapped[str | None] = mapped_column(ForeignKey("users.id"), nullable=True)
claimed_at: Mapped[str] = mapped_column(String, default="")
doing_at: Mapped[str] = mapped_column(String, default="")
publisher_id: Mapped[str | None] = mapped_column(ForeignKey("users.id"), nullable=True) # 发包方(用户)
publisher_org_id: Mapped[str | None] = mapped_column(ForeignKey("organizations.id"), nullable=True)
publisher_name: Mapped[str] = mapped_column(String, default="")
# ── 多端任务体系扩展字段 ──
publisher_role: Mapped[str] = mapped_column(String, default="") # enterprise/operator/park
visibility: Mapped[str] = mapped_column(String, default="public") # public/assigned_only/c_visible
c_visible: Mapped[bool] = mapped_column(Boolean, default=True) # 是否进 C 端任务广场
park_public: Mapped[bool] = mapped_column(Boolean, default=False) # 是否公有任务(各园区大屏可见/本园可接)
assign_type: Mapped[str] = mapped_column(String, default="") # opc/park(指派模式)
assign_park_id: Mapped[str | None] = mapped_column(String, nullable=True) # 指派给某园区
assign_opc_id: Mapped[str | None] = mapped_column(String, nullable=True) # 指派给某 OPC
park_id: Mapped[str | None] = mapped_column(String, nullable=True) # 归属园区(园区发布/专属)
park_released: Mapped[bool] = mapped_column(Boolean, default=False) # 园区内已发单(园区企业可抢)
bid_quota: Mapped[int] = mapped_column(Integer, default=0) # 竞标报名人数上限(0=不限)
win_quota: Mapped[int] = mapped_column(Integer, default=0) # 竞标中标人数(默认1)
eligibility: Mapped[str] = mapped_column(Text, default="{}") # 接单资格条件(JSON 集)
settle_mode: Mapped[str] = mapped_column(String, default="operator_escrow") # 资金托管方式
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class TaskClaim(Base):
"""任务接单流水(扫码/抢单/投标/指派/推荐),rich 记录任务状态流转历史。"""
__tablename__ = "task_claims"
id: Mapped[str] = mapped_column(String, primary_key=True)
task_id: Mapped[str] = mapped_column(
ForeignKey("tasks.id", ondelete="CASCADE"), nullable=False, index=True,
)
claimer_user_id: Mapped[str] = mapped_column(
ForeignKey("users.id", ondelete="SET NULL"), nullable=True,
)
claimer_name: Mapped[str] = mapped_column(String, default="")
claim_source: Mapped[str] = mapped_column(String, default="scan") # scan/grab/bid/assign/recommend
claimed_at: Mapped[str] = mapped_column(String, default="")
status: Mapped[str] = mapped_column(String, default="claimed") # claimed/doing/completed/withdrawn/assigned/recommended
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class TaskCategory(Base):
"""任务分类字典(顶层 35 类,取自 任务类别.json)。"""
__tablename__ = "task_categories"
id: Mapped[str] = mapped_column(String, primary_key=True)
name: Mapped[str] = mapped_column(String, default="", index=True)
sort: Mapped[int] = mapped_column(Integer, default=0)
modes: Mapped[str] = mapped_column(String, default="") # 兼容位掩码 hint(逗号分隔,可选)
status: Mapped[str] = mapped_column(String, default="active") # active/disabled
class ServiceProvider(Base):
"""服务商(运营端审核/评级/考核)。"""
__tablename__ = "service_providers"
id: Mapped[str] = mapped_column(String, primary_key=True)
name: Mapped[str] = mapped_column(String, default="")
category: Mapped[str] = mapped_column(String, default="") # 财税/工商/法务/知识产权/云服务...
org_id: Mapped[str | None] = mapped_column(ForeignKey("organizations.id"), nullable=True)
level: Mapped[str] = mapped_column(String, default="certified") # certified/premium/gold/official
rating: Mapped[float] = mapped_column(Float, default=5.0)
order_count: Mapped[int] = mapped_column(Integer, default=0)
status: Mapped[str] = mapped_column(String, default="pending") # pending/active/blacklisted
contact: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class ContentItem(Base):
"""平台内容(政策/课程/资讯/公告/活动)。"""
__tablename__ = "content_items"
id: Mapped[str] = mapped_column(String, primary_key=True)
type: Mapped[str] = mapped_column(String, default="news") # policy/course/news/notice/activity
title: Mapped[str] = mapped_column(String, default="")
summary: Mapped[str] = mapped_column(String, default="")
body: Mapped[str] = mapped_column(Text, default="")
publisher_id: Mapped[str | None] = mapped_column(ForeignKey("users.id"), nullable=True)
# 资讯富字段:封面/图集/视频/外链/发布人
cover: Mapped[str] = mapped_column(String, default="") # 加宽封面图 URL3.35:1
cover_small: Mapped[str] = mapped_column(String, default="") # 小封面图 URL1:1,可选)
images_json: Mapped[str] = mapped_column(Text, default="[]") # 图集(JSON url 数组)
video: Mapped[str] = mapped_column(String, default="") # 视频 URL
video_cover: Mapped[str] = mapped_column(String, default="") # 视频封面
link: Mapped[str] = mapped_column(String, default="") # 外链
publisher_name: Mapped[str] = mapped_column(String, default="") # 发布人昵称快照
publisher_avatar: Mapped[str] = mapped_column(String, default="") # 发布人头像快照
read_count: Mapped[int] = mapped_column(Integer, default=0) # 阅读数
like_count: Mapped[int] = mapped_column(Integer, default=0) # 点赞数
share_count: Mapped[int] = mapped_column(Integer, default=0) # 分享数(每转发一次 +1
card_mode: Mapped[str] = mapped_column(String, default="big") # big 大图 | small 小图(运营端设)
is_public: Mapped[bool] = mapped_column(Boolean, default=True) # 是否公开(公开=C端,否则仅园区大屏)
source: Mapped[str] = mapped_column(String, default="operator") # operator 运营端 | carrier 园区端
tenant_id: Mapped[str] = mapped_column(String, default="") # 园区端发布所属园区
priority: Mapped[int] = mapped_column(Integer, default=0) # 优先级 0-999 越大越靠前(C端排序)
status: Mapped[str] = mapped_column(String, default="draft") # draft/pending/published/offlinepending=待审核)
published_at: Mapped[str] = mapped_column(String, default="") # 发布时间(可未来=定时发布;C端到点才可见)
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class ContentLike(Base):
"""资讯点赞(一人一赞,可取消)。"""
__tablename__ = "content_likes"
id: Mapped[str] = mapped_column(String, primary_key=True)
content_id: Mapped[str] = mapped_column(String, default="", index=True)
user_id: Mapped[str] = mapped_column(String, default="", index=True)
created_at: Mapped[str] = mapped_column(String, default="")
class ContentComment(Base):
"""资讯留言(支持回复:reply_to 为空=顶层,否则为父评论 id)。"""
__tablename__ = "content_comments"
id: Mapped[str] = mapped_column(String, primary_key=True)
content_id: Mapped[str] = mapped_column(String, default="", index=True)
user_id: Mapped[str] = mapped_column(String, default="")
username: Mapped[str] = mapped_column(String, default="")
nickname: Mapped[str] = mapped_column(String, default="")
avatar: Mapped[str] = mapped_column(String, default="")
content: Mapped[str] = mapped_column(Text, default="")
reply_to: Mapped[str] = mapped_column(String, default="") # 父评论 id(回复嵌套)
like_count: Mapped[int] = mapped_column(Integer, default=0) # 评论点赞数
created_at: Mapped[str] = mapped_column(String, default="")
class ContentCommentLike(Base):
"""资讯评论点赞(一人一赞,可取消)。"""
__tablename__ = "content_comment_likes"
id: Mapped[str] = mapped_column(String, primary_key=True)
comment_id: Mapped[str] = mapped_column(String, default="", index=True)
user_id: Mapped[str] = mapped_column(String, default="", index=True)
created_at: Mapped[str] = mapped_column(String, default="")
class SystemConfig(Base):
"""平台系统配置(键值)。"""
__tablename__ = "system_configs"
key: Mapped[str] = mapped_column(String, primary_key=True)
value: Mapped[str] = mapped_column(String, default="")
description: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class PortalDashboard(Base):
"""端口工作台聚合数据(按端口存 JSON 载荷,全部由服务端提供)。"""
__tablename__ = "portal_dashboards"
port: Mapped[str] = mapped_column(String, primary_key=True)
payload: Mapped[str] = mapped_column(Text, default="{}")
updated_at: Mapped[str] = mapped_column(String, default="")
class PortalPage(Base):
"""端口子页面数据(按 端口+页面 存 JSON 载荷,全部由服务端提供)。"""
__tablename__ = "portal_pages"
port: Mapped[str] = mapped_column(String, primary_key=True)
page: Mapped[str] = mapped_column(String, primary_key=True)
payload: Mapped[str] = mapped_column(Text, default="{}")
updated_at: Mapped[str] = mapped_column(String, default="")
# ── 投资人端(投融资 · 路演 · 培训)──────────────────────────────────────
class InvestorPreference(Base):
"""投资人投资方向偏好。"""
__tablename__ = "investor_preferences"
user_id: Mapped[str] = mapped_column(
ForeignKey("users.id", ondelete="CASCADE"), primary_key=True,
)
industries: Mapped[str] = mapped_column(String, default="[]") # JSON list
stage: Mapped[str] = mapped_column(String, default="") # seed/angel/series_a/...
amount_min: Mapped[int] = mapped_column(Integer, default=0)
amount_max: Mapped[int] = mapped_column(Integer, default=0)
region_id: Mapped[str | None] = mapped_column(ForeignKey("regions.id"), nullable=True)
updated_at: Mapped[str] = mapped_column(String, default="")
class Roadshow(Base):
"""投融资路演活动(线上/线下/混合),支持按发布主体与范围审核。"""
__tablename__ = "roadshows"
id: Mapped[str] = mapped_column(String, primary_key=True)
publisher_id: Mapped[str] = mapped_column(String, default="")
publisher_role: Mapped[str] = mapped_column(String, default="investor") # investor/government/operator/carrier/enterprise
title: Mapped[str] = mapped_column(String, default="")
summary: Mapped[str] = mapped_column(String, default="")
activity_type: Mapped[str] = mapped_column(String, default="online") # online/offline/hybrid
scope_type: Mapped[str] = mapped_column(String, default="all") # all/region/org
region_id: Mapped[str | None] = mapped_column(ForeignKey("regions.id"), nullable=True)
start_at: Mapped[str] = mapped_column(String, default="")
end_at: Mapped[str] = mapped_column(String, default="")
register_deadline: Mapped[str] = mapped_column(String, default="")
quota: Mapped[int] = mapped_column(Integer, default=0)
venue: Mapped[str] = mapped_column(String, default="") # 线下地点/直播间
live_url: Mapped[str] = mapped_column(String, default="")
status: Mapped[str] = mapped_column(String, default="draft") # draft/submitted/reviewing/published/registering/ongoing/ended/archived/rejected/cancelled
review_comment: Mapped[str] = mapped_column(String, default="")
need_review: Mapped[bool] = mapped_column(Boolean, default=True)
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class RoadshowRegistration(Base):
"""路演活动报名(项目方/投资人)。"""
__tablename__ = "roadshow_registrations"
id: Mapped[str] = mapped_column(String, primary_key=True)
roadshow_id: Mapped[str] = mapped_column(
ForeignKey("roadshows.id", ondelete="CASCADE"), nullable=False,
)
user_id: Mapped[str] = mapped_column(
ForeignKey("users.id", ondelete="CASCADE"), nullable=False,
)
role: Mapped[str] = mapped_column(String, default="investor") # investor/project
status: Mapped[str] = mapped_column(String, default="applying") # applying/approved/attended/absent
note: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")
class InvestmentIntent(Base):
"""投资意向/约谈/尽调。"""
__tablename__ = "investment_intents"
id: Mapped[str] = mapped_column(String, primary_key=True)
investor_id: Mapped[str] = mapped_column(
ForeignKey("users.id", ondelete="CASCADE"), nullable=False,
)
project_id: Mapped[str] = mapped_column(String, default="")
project_name: Mapped[str] = mapped_column(String, default="")
status: Mapped[str] = mapped_column(String, default="interested") # interested/contacted/meeting/term_sheet/invested/declined
message: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class Bid(Base):
"""任务竞标(企业端竞标模式发标)。"""
__tablename__ = "bids"
id: Mapped[str] = mapped_column(String, primary_key=True)
task_id: Mapped[str] = mapped_column(
ForeignKey("tasks.id", ondelete="CASCADE"), nullable=False,
)
opc_id: Mapped[str] = mapped_column(String, default="")
opc_name: Mapped[str] = mapped_column(String, default="")
quote: Mapped[int] = mapped_column(Integer, default=0)
plan: Mapped[str] = mapped_column(String, default="")
status: Mapped[str] = mapped_column(String, default="submitted") # submitted/win/lost
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class SubsidyApplication(Base):
"""补贴申报(政务三级审批:区县→市→省→发放)。"""
__tablename__ = "subsidy_applications"
id: Mapped[str] = mapped_column(String, primary_key=True)
opc_id: Mapped[str] = mapped_column(String, default="")
opc_name: Mapped[str] = mapped_column(String, default="")
title: Mapped[str] = mapped_column(String, default="")
amount: Mapped[int] = mapped_column(Integer, default=0)
region_id: Mapped[str | None] = mapped_column(ForeignKey("regions.id"), nullable=True)
status: Mapped[str] = mapped_column(String, default="applying") # applying/district_review/city_review/province_review/approved/paid/rejected
comment: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class ServiceReferral(Base):
"""载体-服务商引荐(三方绑定:载体引荐服务商→服务园区内 OPC)。"""
__tablename__ = "service_referrals"
id: Mapped[str] = mapped_column(String, primary_key=True)
carrier_id: Mapped[str] = mapped_column(String, default="")
provider_id: Mapped[str] = mapped_column(String, default="")
provider_name: Mapped[str] = mapped_column(String, default="")
opc_id: Mapped[str] = mapped_column(String, default="")
opc_name: Mapped[str] = mapped_column(String, default="")
status: Mapped[str] = mapped_column(String, default="referred") # referred/accepted/completed/declined
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class TrainingEnrollment(Base):
"""投融资培训报名/证书。"""
__tablename__ = "training_enrollments"
id: Mapped[str] = mapped_column(String, primary_key=True)
training_id: Mapped[str] = mapped_column(String, default="")
training_name: Mapped[str] = mapped_column(String, default="")
user_id: Mapped[str] = mapped_column(
ForeignKey("users.id", ondelete="CASCADE"), nullable=False,
)
status: Mapped[str] = mapped_column(String, default="applying") # applying/enrolled/completed/certificate
created_at: Mapped[str] = mapped_column(String, default="")
# ── 横切能力:结算/合同/争议/评价/通知 ────────────────────────────────────
class Escrow(Base):
"""任务资金托管/结算。"""
__tablename__ = "escrows"
id: Mapped[str] = mapped_column(String, primary_key=True)
task_id: Mapped[str] = mapped_column(
ForeignKey("tasks.id", ondelete="CASCADE"), nullable=False,
)
task_title: Mapped[str] = mapped_column(String, default="")
amount: Mapped[int] = mapped_column(Integer, default=0)
commission: Mapped[int] = mapped_column(Integer, default=0) # 平台佣金
status: Mapped[str] = mapped_column(String, default="deposited") # deposited/frozen/released/refunded
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class Contract(Base):
"""任务电子合同。"""
__tablename__ = "contracts"
id: Mapped[str] = mapped_column(String, primary_key=True)
task_id: Mapped[str] = mapped_column(
ForeignKey("tasks.id", ondelete="CASCADE"), nullable=False,
)
task_title: Mapped[str] = mapped_column(String, default="")
enterprise_id: Mapped[str] = mapped_column(String, default="")
opc_id: Mapped[str] = mapped_column(String, default="")
status: Mapped[str] = mapped_column(String, default="signed") # draft/signed/terminated
content: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")
class Dispute(Base):
"""任务争议。"""
__tablename__ = "disputes"
id: Mapped[str] = mapped_column(String, primary_key=True)
task_id: Mapped[str] = mapped_column(
ForeignKey("tasks.id", ondelete="CASCADE"), nullable=False,
)
task_title: Mapped[str] = mapped_column(String, default="")
initiator: Mapped[str] = mapped_column(String, default="")
reason: Mapped[str] = mapped_column(String, default="")
status: Mapped[str] = mapped_column(String, default="opened") # opened/mediating/resolved/closed
resolution: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")
class Rating(Base):
"""任务互评。"""
__tablename__ = "ratings"
id: Mapped[str] = mapped_column(String, primary_key=True)
task_id: Mapped[str] = mapped_column(
ForeignKey("tasks.id", ondelete="CASCADE"), nullable=False,
)
from_id: Mapped[str] = mapped_column(String, default="")
to_id: Mapped[str] = mapped_column(String, default="")
score: Mapped[int] = mapped_column(Integer, default=5) # 1..5
comment: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")
class Notification(Base):
"""站内通知。"""
__tablename__ = "notifications"
id: Mapped[str] = mapped_column(String, primary_key=True)
user_id: Mapped[str] = mapped_column(
ForeignKey("users.id", ondelete="CASCADE"), nullable=False,
)
type: Mapped[str] = mapped_column(String, default="system") # task/policy/order/subsidy/system
title: Mapped[str] = mapped_column(String, default="")
content: Mapped[str] = mapped_column(String, default="")
read: Mapped[bool] = mapped_column(Boolean, default=False)
created_at: Mapped[str] = mapped_column(String, default="")
# ── OPC 超级个体业务模型(工作台/我的任务/财务/消息)────────────────────
class OpcProfile(Base):
"""OPC 超级个体档案(信用评分等)。"""
__tablename__ = "opc_profiles"
user_id: Mapped[str] = mapped_column(
ForeignKey("users.id", ondelete="CASCADE"), primary_key=True,
)
credit_score: Mapped[int] = mapped_column(Integer, default=80)
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class FinanceRecord(Base):
"""OPC 财务流水(收入/支出)。"""
__tablename__ = "finance_records"
id: Mapped[str] = mapped_column(String, primary_key=True)
user_id: Mapped[str] = mapped_column(
ForeignKey("users.id", ondelete="CASCADE"), nullable=False,
)
category: Mapped[str] = mapped_column(String, default="income") # income | expense
amount: Mapped[int] = mapped_column(Integer, default=0)
date: Mapped[str] = mapped_column(String, default="") # YYYY-MM-DD
note: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")
class Message(Base):
"""OPC 站内消息。"""
__tablename__ = "messages"
id: Mapped[str] = mapped_column(String, primary_key=True)
user_id: Mapped[str] = mapped_column(
ForeignKey("users.id", ondelete="CASCADE"), nullable=False,
)
msg_type: Mapped[str] = mapped_column(String, default="system") # task/policy/service/agent/system
title: Mapped[str] = mapped_column(String, default="")
content: Mapped[str] = mapped_column(String, default="")
read: Mapped[bool] = mapped_column(Boolean, default=False)
created_at: Mapped[str] = mapped_column(String, default="")
class OpcTask(Base):
"""OPC 个人任务看板(「我的任务」:进行中/已完成/紧急)。"""
__tablename__ = "opc_tasks"
id: Mapped[str] = mapped_column(String, primary_key=True)
user_id: Mapped[str] = mapped_column(
ForeignKey("users.id", ondelete="CASCADE"), nullable=False,
)
title: Mapped[str] = mapped_column(String, default="")
status: Mapped[str] = mapped_column(String, default="in_progress") # in_progress/completed/urgent
budget: Mapped[int] = mapped_column(Integer, default=0)
deadline: Mapped[str] = mapped_column(String, default="")
progress: Mapped[int] = mapped_column(Integer, default=0)
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
# ===========================================================================
# 培训业务子应用(原 app/training 独立 opc.db → 并入唯一总库)
# ===========================================================================
class TrainingAccount(Base):
"""培训站账号(原 accounts,含手机/微信登录)。"""
__tablename__ = "accounts"
id: Mapped[str | None] = mapped_column(String, primary_key=True)
username: Mapped[str | None] = mapped_column(String, unique=True, nullable=False)
wxid: Mapped[str | None] = mapped_column(String, default="")
phone: Mapped[str | None] = mapped_column(String, default="")
contact: Mapped[str | None] = mapped_column(String, default="")
name: Mapped[str | None] = mapped_column(String, default="")
avatar: Mapped[str | None] = mapped_column(String, default="")
password: Mapped[str | None] = mapped_column(String, default="")
phone_bound: Mapped[int | None] = mapped_column(Integer, default=0)
identities: Mapped[str | None] = mapped_column(Text, default="[]")
status_label: Mapped[str | None] = mapped_column(String, default="")
topics: Mapped[str | None] = mapped_column(Text, default="")
source: Mapped[str | None] = mapped_column(String, default="")
created_at: Mapped[str | None] = mapped_column(String, default="")
class Event(Base):
__tablename__ = "events"
id: Mapped[str | None] = mapped_column(String, primary_key=True)
type: Mapped[str | None] = mapped_column(String, default="")
mode: Mapped[str | None] = mapped_column(String, default="offline")
title: Mapped[str | None] = mapped_column(String, default="")
subtitle: Mapped[str | None] = mapped_column(String, default="")
desc: Mapped[str | None] = mapped_column(Text, default="")
location: Mapped[str | None] = mapped_column(String, default="")
host: Mapped[str | None] = mapped_column(String, default="")
image: Mapped[str | None] = mapped_column(String, default="")
link: Mapped[str | None] = mapped_column(String, default="")
start_at: Mapped[str | None] = mapped_column(String, default="")
end_at: Mapped[str | None] = mapped_column(String, default="")
checkin_at: Mapped[str | None] = mapped_column(String, default="")
duration_min: Mapped[int | None] = mapped_column(Integer, default=90)
capacity: Mapped[int | None] = mapped_column(Integer, default=0)
show_capacity: Mapped[int | None] = mapped_column(Integer, default=0)
audit_mode: Mapped[str | None] = mapped_column(String, default="auto")
status: Mapped[str | None] = mapped_column(String, default="open")
price_fen: Mapped[int | None] = mapped_column(Integer, default=0) # 定价(分),0=免费
# ── 活动体系扩展(区域/类型/范围/审核/富文本/外链报名) ──
region: Mapped[str | None] = mapped_column(String, default="") # 昆明/曲靖/大理/丽江/版纳/楚雄/红河/其他
category: Mapped[str | None] = mapped_column(String, default="") # 峰会/竞赛/沙龙/培训/展会/投融资
scope: Mapped[str | None] = mapped_column(String, default="public") # park 本园区 | public 公开
target_tenant_id: Mapped[str | None] = mapped_column(String, default="") # scope=park 时目标园区 id
review_status: Mapped[str | None] = mapped_column(String, default="approved") # draft|pending|approved|rejected
review_comment: Mapped[str | None] = mapped_column(String, default="")
review_by: Mapped[str | None] = mapped_column(String, default="")
review_at: Mapped[str | None] = mapped_column(String, default="")
body: Mapped[str | None] = mapped_column(Text, default="") # 活动介绍(富文本 HTML
notice: Mapped[str | None] = mapped_column(Text, default="") # 活动注意事项(与时间/地点/人数一并展示)
external_url: Mapped[str | None] = mapped_column(String, default="") # 外链报名地址
signup_mode: Mapped[str | None] = mapped_column(String, default="mini") # mini 小程序报名 | external 外链报名
publisher_id: Mapped[str | None] = mapped_column(String, default="") # 发布者
publisher_name: Mapped[str | None] = mapped_column(String, default="")
class Booking(Base):
__tablename__ = "bookings"
id: Mapped[str | None] = mapped_column(String, primary_key=True)
created_at: Mapped[str | None] = mapped_column(String, default="")
status: Mapped[str | None] = mapped_column(String, default="pending")
audit_status: Mapped[str | None] = mapped_column(String, default="pending")
username: Mapped[str | None] = mapped_column(String, default="")
name: Mapped[str | None] = mapped_column(String, default="")
contact: Mapped[str | None] = mapped_column(String, default="")
status_label: Mapped[str | None] = mapped_column(String, default="")
want: Mapped[str | None] = mapped_column(Text, default="")
event_id: Mapped[str | None] = mapped_column(String, default="")
event_title: Mapped[str | None] = mapped_column(String, default="")
event_start: Mapped[str | None] = mapped_column(String, default="")
topics: Mapped[str | None] = mapped_column(Text, default="")
question: Mapped[str | None] = mapped_column(Text, default="")
source: Mapped[str | None] = mapped_column(String, default="")
checkin_at: Mapped[str | None] = mapped_column(String, default="")
pay_status: Mapped[str | None] = mapped_column(String, default="") # ''|unpaid|paid(付费活动)
order_no: Mapped[str | None] = mapped_column(String, default="") # 关联 event_orders.order_no
appeal_status: Mapped[str | None] = mapped_column(String, default="") # ''|pending|approved|rejected(爽约申诉)
appeal_reason: Mapped[str | None] = mapped_column(Text, default="")
appeal_at: Mapped[str | None] = mapped_column(String, default="")
class Test(Base):
__tablename__ = "tests"
id: Mapped[str | None] = mapped_column(String, primary_key=True)
created_at: Mapped[str | None] = mapped_column(String, default="")
username: Mapped[str | None] = mapped_column(String, default="")
type_code: Mapped[str | None] = mapped_column(String, default="")
persona: Mapped[str | None] = mapped_column(String, default="")
adapt_index: Mapped[int | None] = mapped_column(Integer, default=0)
adapt_level: Mapped[str | None] = mapped_column(String, default="")
tracks: Mapped[str | None] = mapped_column(Text, default="")
version: Mapped[str | None] = mapped_column(String, default="")
class Course(Base):
__tablename__ = "courses"
id: Mapped[str | None] = mapped_column(String, primary_key=True)
category: Mapped[str | None] = mapped_column(String, default="")
level: Mapped[str | None] = mapped_column(String, default="")
title: Mapped[str | None] = mapped_column(String, default="")
subtitle: Mapped[str | None] = mapped_column(String, default="")
desc: Mapped[str | None] = mapped_column(Text, default="")
price: Mapped[float | None] = mapped_column(Float, default=0.0)
status: Mapped[str | None] = mapped_column(String, default="draft")
start_at: Mapped[str | None] = mapped_column(String, default="")
end_at: Mapped[str | None] = mapped_column(String, default="")
venue: Mapped[str | None] = mapped_column(String, default="")
quota: Mapped[int | None] = mapped_column(Integer, default=0)
image: Mapped[str | None] = mapped_column(String, default="")
host: Mapped[str | None] = mapped_column(String, default="")
created_at: Mapped[str | None] = mapped_column(String, default="")
class PolicyLog(Base):
__tablename__ = "policy_logs"
id: Mapped[str | None] = mapped_column(String, primary_key=True)
created_at: Mapped[str | None] = mapped_column(String, default="")
username: Mapped[str | None] = mapped_column(String, default="")
answers: Mapped[str | None] = mapped_column(Text, default="")
policies_count: Mapped[int | None] = mapped_column(Integer, default=0)
subsidies_count: Mapped[int | None] = mapped_column(Integer, default=0)
loans_count: Mapped[int | None] = mapped_column(Integer, default=0)
summary: Mapped[str | None] = mapped_column(Text, default="")
class PlanLog(Base):
__tablename__ = "plan_logs"
id: Mapped[str | None] = mapped_column(String, primary_key=True)
created_at: Mapped[str | None] = mapped_column(String, default="")
username: Mapped[str | None] = mapped_column(String, default="")
region: Mapped[str | None] = mapped_column(String, default="")
status: Mapped[str | None] = mapped_column(String, default="")
need_park: Mapped[int | None] = mapped_column(Integer, default=0)
has_staff: Mapped[int | None] = mapped_column(Integer, default=0)
steps_count: Mapped[int | None] = mapped_column(Integer, default=0)
class SurveyLog(Base):
__tablename__ = "survey_logs"
id: Mapped[str | None] = mapped_column(String, primary_key=True)
created_at: Mapped[str | None] = mapped_column(String, default="")
username: Mapped[str | None] = mapped_column(String, default="")
source: Mapped[str | None] = mapped_column(String, default="")
answers: Mapped[str | None] = mapped_column(Text, default="")
# ===========================================================================
# 园区子应用(原 app/park 独立 park.db → 并入唯一总库)
# ===========================================================================
class ParkTenant(Base):
__tablename__ = "park_tenants"
id: Mapped[str] = mapped_column(String, primary_key=True)
name: Mapped[str] = mapped_column(String, default="")
intro_json: Mapped[str] = mapped_column(Text, default="[]")
username: Mapped[str] = mapped_column(String, default="")
salt: Mapped[str] = mapped_column(String, default="")
password_hash: Mapped[str] = mapped_column(String, default="")
admin_username: Mapped[str] = mapped_column(String, default="")
status: Mapped[str] = mapped_column(String, default="active")
data_json: Mapped[str] = mapped_column(Text, default="{}")
agent_json: Mapped[str] = mapped_column(Text, default="{}")
operator_user_id: Mapped[str] = mapped_column(String, default="") # 园区归属载体账号,园区端据此只审本园区
# ── 载体资料(云南载体地图对外展示,0034) ──
lng: Mapped[float | None] = mapped_column(Float, nullable=True) # 经度(点阵地图渲染)
lat: Mapped[float | None] = mapped_column(Float, nullable=True) # 纬度
cover: Mapped[str] = mapped_column(String, default="") # 封面图 URL
address: Mapped[str] = mapped_column(String, default="") # 详细地址
city: Mapped[str] = mapped_column(String, default="") # 区域(昆明/曲靖/大理/丽江/版纳/楚雄/红河/其他)
intro_html: Mapped[str] = mapped_column(Text, default="") # 园区介绍(富文本 HTML)
policy_html: Mapped[str] = mapped_column(Text, default="") # 政策支持(富文本 HTML)
admission_html: Mapped[str] = mapped_column(Text, default="") # 入驻流程(富文本 HTML)
contact: Mapped[str] = mapped_column(String, default="") # 联系方式
tags: Mapped[str] = mapped_column(String, default="") # 标签(逗号分隔)
stats_json: Mapped[str] = mapped_column(Text, default="") # 展示统计 JSON [{label,value}]
profile_status: Mapped[str] = mapped_column(String, default="approved") # approved 已生效 | pending 载体端改动待审
profile_draft_json: Mapped[str] = mapped_column(Text, default="") # 载体端待审草案(JSON)
profile_review_comment: Mapped[str] = mapped_column(String, default="")
profile_reviewed_at: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")
class ParkCompany(Base):
__tablename__ = "park_companies"
id: Mapped[str] = mapped_column(String, primary_key=True)
tenant_id: Mapped[str | None] = mapped_column(ForeignKey("park_tenants.id", ondelete="CASCADE"), nullable=True, index=True)
company_kind: Mapped[str] = mapped_column(String, default="park_entered") # park_entered 园区入驻 | independent 独立(tenant_id 为空)
name: Mapped[str] = mapped_column(String, default="")
zone: Mapped[str] = mapped_column(String, default="")
room: Mapped[str] = mapped_column(String, default="")
industry: Mapped[str] = mapped_column(String, default="")
bio: Mapped[str] = mapped_column(Text, default="")
founder: Mapped[str] = mapped_column(String, default="")
status: Mapped[str] = mapped_column(String, default="applying")
employees: Mapped[int | None] = mapped_column(Integer, nullable=True)
# 企业丰富资料(参考入园申请表 §二 企业信息)
legal_person: Mapped[str] = mapped_column(String, default="") # 法定代表人
legal_phone: Mapped[str] = mapped_column(String, default="") # 法人联系电话
registered_capital: Mapped[str] = mapped_column(String, default="") # 注册资本(万元)
company_type: Mapped[str] = mapped_column(String, default="") # 企业类型/性质
honors: Mapped[str] = mapped_column(Text, default="") # 所获政策/荣誉
address: Mapped[str] = mapped_column(String, default="") # 企业地址
contact_phone: Mapped[str] = mapped_column(String, default="") # 企业联系人电话
founded_at: Mapped[str] = mapped_column(String, default="") # 成立时间
emp_total: Mapped[int | None] = mapped_column(Integer, nullable=True) # 职工总数
emp_grad: Mapped[int | None] = mapped_column(Integer, nullable=True) # 毕业大学生
emp_layoff: Mapped[int | None] = mapped_column(Integer, nullable=True) # 失业人员
emp_veteran: Mapped[int | None] = mapped_column(Integer, nullable=True) # 退役军人
emp_migrant: Mapped[int | None] = mapped_column(Integer, nullable=True) # 返乡农民工
# 企业算力(只增不减):折扣% off 模型价;配额为发放给成员的算力额度
compute_discount: Mapped[int] = mapped_column(Integer, default=0) # 折扣%0-100,单调非降)
compute_quota: Mapped[int] = mapped_column(Integer, default=0) # 企业算力配额(单调非降/增量)
compute_quota_used: Mapped[int] = mapped_column(Integer, default=0) # 已分配/已用配额(统计)
engine_group: Mapped[str] = mapped_column(String, default="") # 引擎用户组名(折扣倍率载体)
owner_user_id: Mapped[str] = mapped_column(String, default="") # 负责人/管理员账号id(必填)
created_at: Mapped[str] = mapped_column(String, default="")
class ParkKbDoc(Base):
__tablename__ = "park_kb_docs"
id: Mapped[str] = mapped_column(String, primary_key=True)
tenant_id: Mapped[str] = mapped_column(ForeignKey("park_tenants.id", ondelete="CASCADE"), nullable=False, index=True)
grp: Mapped[str] = mapped_column(String, default="general")
title: Mapped[str] = mapped_column(String, default="")
content_md: Mapped[str] = mapped_column(Text, default="")
created_at: Mapped[str] = mapped_column(String, default="")
class ParkSetting(Base):
"""园区全局配置 kv(如视频识别开关/地址),admin 经 /park/admin/* 读写,运行时不建表/不灌种子。"""
__tablename__ = "park_settings"
key: Mapped[str] = mapped_column(String, primary_key=True)
value: Mapped[str] = mapped_column(Text, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class ParkAdmission(Base):
"""园区入驻申请(C端 小程序/网页提交,园区/运营端审核)。
表单字段以 JSON 存入 form_json(申请人/企业/项目/入驻需求),
上传资料 URL 存 docs_json(创业计划书/身份证/学历/执照/资质等)。
"""
__tablename__ = "park_admissions"
id: Mapped[str] = mapped_column(String, primary_key=True)
tenant_id: Mapped[str] = mapped_column(String, default="") # 所选园区 id
tenant_name: Mapped[str] = mapped_column(String, default="") # 冗余园区名(展示)
user_id: Mapped[str] = mapped_column(String, default="", index=True) # 申请人平台用户 id
username: Mapped[str] = mapped_column(String, default="") # 申请人登录名
applicant_name: Mapped[str] = mapped_column(String, default="") # 申请人姓名(快速列表展示)
contact_phone: Mapped[str] = mapped_column(String, default="") # 联系电话(列表展示)
status: Mapped[str] = mapped_column(String, default="pending") # pending/reviewing/approved/rejected
form_json: Mapped[str] = mapped_column(Text, default="{}") # 结构化表单(申请人/企业/项目/需求)
docs_json: Mapped[str] = mapped_column(Text, default="{}") # 上传资料 URL 集合
source: Mapped[str] = mapped_column(String, default="miniprogram") # miniprogram|web
review_comment: Mapped[str] = mapped_column(String, default="")
reviewed_by: Mapped[str] = mapped_column(String, default="")
reviewed_at: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class ParkScreen(Base):
__tablename__ = "park_screens"
id: Mapped[str] = mapped_column(String, primary_key=True)
tenant_id: Mapped[str | None] = mapped_column(ForeignKey("park_tenants.id", ondelete="CASCADE"), nullable=True, index=True)
device_id: Mapped[str] = mapped_column(String, default="", index=True)
name: Mapped[str] = mapped_column(String, default="")
role: Mapped[str] = mapped_column(String, default="main")
location: Mapped[str] = mapped_column(String, default="")
status: Mapped[str] = mapped_column(String, default="unbound") # unbound | bound
code: Mapped[str] = mapped_column(String, default="") # 待绑定连接码
code_expires: Mapped[str] = mapped_column(String, default="") # 码过期时间(ISO)
bound_at: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")
class OpcCertification(Base):
"""OPC 认证申请表(用户提交资料 → 运营方审核)。"""
__tablename__ = "opc_certifications"
id: Mapped[str] = mapped_column(String, primary_key=True)
user_id: Mapped[str] = mapped_column(String, default="", index=True)
username: Mapped[str] = mapped_column(String, default="")
real_name: Mapped[str] = mapped_column(String, default="")
gender: Mapped[str] = mapped_column(String, default="")
address: Mapped[str] = mapped_column(String, default="")
industry: Mapped[str] = mapped_column(String, default="")
ability: Mapped[str] = mapped_column(Text, default="")
phone: Mapped[str] = mapped_column(String, default="")
docs_json: Mapped[str] = mapped_column(Text, default="{}")
status: Mapped[str] = mapped_column(String, default="pending")
review_comment: Mapped[str] = mapped_column(String, default="")
reviewed_by: Mapped[str] = mapped_column(String, default="")
reviewed_at: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class ParkTransfer(Base):
"""OPC/企业 转园申请表(运营端/园区端/企业管理员/用户本人发起 → 转出园区+转入园区两级审核,运营端兜底)。"""
__tablename__ = "park_transfers"
id: Mapped[str] = mapped_column(String, primary_key=True)
user_id: Mapped[str] = mapped_column(String, default="", index=True)
username: Mapped[str] = mapped_column(String, default="")
from_park_id: Mapped[str] = mapped_column(String, default="")
from_park_name: Mapped[str] = mapped_column(String, default="")
to_park_id: Mapped[str] = mapped_column(String, default="")
to_park_name: Mapped[str] = mapped_column(String, default="")
reason: Mapped[str] = mapped_column(Text, default="")
status: Mapped[str] = mapped_column(String, default="pending") # 当前阶段冗余(对外展示)
# ── 两级审核状态机 ──
stage: Mapped[str] = mapped_column(String, default="pending_from") # pending_from→pending_to→approved/rejected/cancelled
from_status: Mapped[str] = mapped_column(String, default="pending") # pending/approved/rejected
to_status: Mapped[str] = mapped_column(String, default="pending")
from_reviewer_id: Mapped[str] = mapped_column(String, default="")
to_reviewer_id: Mapped[str] = mapped_column(String, default="")
operator_reviewer_id: Mapped[str] = mapped_column(String, default="") # 运营端兜底终审人
from_reviewed_at: Mapped[str] = mapped_column(String, default="")
to_reviewed_at: Mapped[str] = mapped_column(String, default="")
review_comment: Mapped[str] = mapped_column(String, default="")
reviewed_by: Mapped[str] = mapped_column(String, default="")
reviewed_at: Mapped[str] = mapped_column(String, default="")
# ── 扩展:发起方与目标 ──
initiator_role: Mapped[str] = mapped_column(String, default="user") # operator/carrier/enterprise/user
target_kind: Mapped[str] = mapped_column(String, default="user") # user 用户转园 | company 企业整体转园
company_id: Mapped[str] = mapped_column(String, default="") # target_kind=company 时的企业 id
created_at: Mapped[str] = mapped_column(String, default="")
updated_at: Mapped[str] = mapped_column(String, default="")
class ParkMember(Base):
"""用户↔园区 成员关系(多对多)。
用户可同时归属多个园区;users.affiliation/park_id/park_name 为派生展示冗余
(由 services.membership.sync_user_affiliation 统一刷新),任何端口不得直接改写。
"""
__tablename__ = "park_members"
__table_args__ = (UniqueConstraint("user_id", "park_id", name="uq_park_member"),)
id: Mapped[str] = mapped_column(String, primary_key=True)
user_id: Mapped[str] = mapped_column(String, index=True)
park_id: Mapped[str] = mapped_column(String, index=True)
member_type: Mapped[str] = mapped_column(String, default="staff") # admin 园区管理员 | staff 园区成员 | migrated 迁移
status: Mapped[str] = mapped_column(String, default="active") # active | disabled
created_by: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")
class CompanyMember(Base):
"""用户↔企业 成员关系(多对多)。
每家企业至多一名 is_admin=True 的企业管理员(与 park_companies.owner_user_id 同步维护)。
"""
__tablename__ = "company_members"
__table_args__ = (UniqueConstraint("user_id", "company_id", name="uq_company_member"),)
id: Mapped[str] = mapped_column(String, primary_key=True)
user_id: Mapped[str] = mapped_column(String, index=True)
company_id: Mapped[str] = mapped_column(String, index=True)
is_admin: Mapped[bool] = mapped_column(Boolean, default=False) # 企业管理员
member_type: Mapped[str] = mapped_column(String, default="staff") # admin/staff/owner/migrated
status: Mapped[str] = mapped_column(String, default="active")
created_by: Mapped[str] = mapped_column(String, default="")
created_at: Mapped[str] = mapped_column(String, default="")