feat: 合并 Docker Compose、标注表格优化与部署文档

将 platform + CVAT 合并为单文件 docker-compose.yml,完善 .env 与 init/dev_up 脚本;
新增 docs/DEPLOY.md 与更新 README 以支持新机器部署;含数据湖示例、车队地图、
紧凑表格 UI、ADAS det_7cls 路径与批次台账等近期改动。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-16 17:06:31 +08:00
parent 0b8ade048e
commit 483e027482
117 changed files with 5933 additions and 1499 deletions

View File

@@ -28,7 +28,7 @@ ROLE_DEFS: dict[str, tuple[str, list[str]]] = {
]),
"engineer": ("算法工程师", [
"read:catalog", "read:pending", "read:jobs", "read:audit", "read:fleet", "write:fleet",
"write:approval_submit", "write:delivery_submit", "read:deliveries",
"write:approval_submit", "write:approval_review", "write:delivery_submit", "read:deliveries",
"write:labeling_vendor", "write:labeling_assign",
]),
"labeler": ("标注协调", [
@@ -79,6 +79,7 @@ def init_database() -> None:
_ensure_feishu_bitable_columns(db)
_ensure_approval_columns(db)
_ensure_operation_log_columns(db)
_ensure_batch_index_columns(db)
_seed_roles_permissions(db)
_seed_fleet_demo(db)
_import_jsonl_if_empty(db)
@@ -168,18 +169,22 @@ def _import_jsonl_if_empty(db: Session) -> None:
def assign_default_role(db: Session, user: User) -> None:
"""新用户默认角色;支持 open_id / 部门白名单自动 admin。"""
"""新用户默认角色;白名单用户每次登录也会补齐 admin。"""
admin_role = db.query(Role).filter_by(code="admin").first()
user_dept_ids = set(user.feishu_department_ids())
if user.feishu_open_id and user.feishu_open_id in FEISHU_ADMIN_OPEN_IDS:
role_code = "admin"
elif user_dept_ids and user_dept_ids.intersection(FEISHU_ADMIN_DEPARTMENT_IDS):
role_code = "admin"
elif not user.roles:
role_code = "engineer"
else:
if admin_role and admin_role not in user.roles:
user.roles.append(admin_role)
return
if user_dept_ids and user_dept_ids.intersection(FEISHU_ADMIN_DEPARTMENT_IDS):
if admin_role and admin_role not in user.roles:
user.roles.append(admin_role)
return
if user.roles:
return
role_code = "engineer"
role = db.query(Role).filter_by(code=role_code).first()
if role and role not in user.roles:
if role:
user.roles.append(role)
@@ -325,6 +330,10 @@ def _ensure_approval_columns(db: Session) -> None:
_ensure_table_columns(db, "approvals", {"rejection_category": "VARCHAR(32) DEFAULT ''"})
def _ensure_batch_index_columns(db: Session) -> None:
_ensure_table_columns(db, "batch_index", {"archived": "BOOLEAN DEFAULT FALSE"})
def _ensure_operation_log_columns(db: Session) -> None:
"""确保 operation_logs 表存在并包含所有列。"""
inspector_args = {}

View File

@@ -319,6 +319,67 @@ class BatchDelivery(Base):
}
class BatchIndex(Base):
"""批次列表索引:由扫盘/登记/阶段变更写入,列表 API 只读此表。"""
__tablename__ = "batch_index"
campaign_id = Column(String(64), primary_key=True)
project = Column(String(32), nullable=False, index=True)
task = Column(String(64), nullable=True, index=True)
mode = Column(String(64), nullable=True)
batch = Column(String(128), nullable=False, index=True)
pack = Column(String(64), nullable=True)
location = Column(String(32), nullable=False, default="inbox")
stage = Column(String(32), nullable=False, index=True)
batch_path = Column(String(1024), nullable=True)
scope_key = Column(String(128), nullable=True)
engineer = Column(String(128), nullable=True)
format = Column(String(32), nullable=True)
image_count = Column(Integer, nullable=False, default=0)
label_count = Column(Integer, nullable=False, default=0)
has_meta = Column(Boolean, nullable=False, default=False)
registry_only = Column(Boolean, nullable=False, default=False)
next_cli = Column(String(512), nullable=True)
domain = Column(String(32), nullable=True)
domain_label = Column(String(64), nullable=True)
task_label = Column(String(128), nullable=True)
mode_label = Column(String(128), nullable=True)
labeling_profile = Column(String(128), nullable=True)
export_default = Column(String(128), nullable=True)
ml_adapter = Column(String(128), nullable=True)
indexed_at = Column(DateTime(timezone=True), nullable=False)
archived = Column(Boolean, nullable=False, default=False, index=True)
def to_list_row(self) -> dict:
return {
"project": self.project,
"task": self.task,
"mode": self.mode,
"batch": self.batch,
"pack": self.pack,
"stage": self.stage,
"location": self.location,
"path": self.batch_path,
"engineer": self.engineer,
"format": self.format,
"counts": {"images": self.image_count, "labels": self.label_count},
"has_meta": self.has_meta,
"next_cli": self.next_cli,
"scope_key": self.scope_key,
"domain": self.domain,
"domain_label": self.domain_label,
"task_label": self.task_label,
"mode_label": self.mode_label,
"labeling_profile": self.labeling_profile,
"export_default": self.export_default,
"ml_adapter": self.ml_adapter,
"campaign_id": self.campaign_id,
"registry_only": self.registry_only,
"indexed_at": self.indexed_at.isoformat() if self.indexed_at else None,
}
class FeishuBitableLink(Base):
"""HSAP 批次与飞书多维表格行的对应关系。"""