from pathlib import Path import sys from sqlalchemy import text ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(ROOT)) from app.database import engine # noqa: E402 def column_exists(conn, table_name: str, column_name: str) -> bool: return bool( conn.execute( text( """ SELECT COUNT(1) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = :table_name AND column_name = :column_name """ ), {"table_name": table_name, "column_name": column_name}, ).scalar() ) def index_exists(conn, table_name: str, index_name: str) -> bool: return bool( conn.execute( text( """ SELECT COUNT(1) FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = :table_name AND index_name = :index_name """ ), {"table_name": table_name, "index_name": index_name}, ).scalar() ) def main() -> None: with engine.begin() as conn: if not column_exists(conn, "work_session_devices", "released_at"): conn.execute(text("ALTER TABLE work_session_devices ADD COLUMN released_at DATETIME NULL AFTER sort_order")) if not column_exists(conn, "work_session_devices", "released_by"): conn.execute(text("ALTER TABLE work_session_devices ADD COLUMN released_by VARCHAR(20) NULL AFTER released_at")) if not column_exists(conn, "work_session_devices", "release_reason"): conn.execute(text("ALTER TABLE work_session_devices ADD COLUMN release_reason VARCHAR(120) NULL AFTER released_by")) if not index_exists(conn, "work_session_devices", "idx_session_devices_release"): conn.execute(text("CREATE INDEX idx_session_devices_release ON work_session_devices (released_at)")) conn.execute( text( """ CREATE TABLE IF NOT EXISTS mold_lock_feedbacks ( id BIGINT NOT NULL AUTO_INCREMENT, attendance_point_name VARCHAR(128) NOT NULL DEFAULT '', mold_name VARCHAR(255) NOT NULL, process_name VARCHAR(128) NOT NULL DEFAULT '', session_device_id BIGINT NOT NULL, reporter_phone VARCHAR(20) NOT NULL, occupied_phone VARCHAR(20) NOT NULL, status VARCHAR(32) NOT NULL DEFAULT 'pending', read_at DATETIME NULL, handled_at DATETIME NULL, handled_by VARCHAR(20) NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_mold_lock_feedback_point_read (attendance_point_name, read_at, created_at), KEY idx_mold_lock_feedback_status (status, created_at), KEY idx_mold_lock_feedback_device (session_device_id), CONSTRAINT fk_mold_lock_feedback_device FOREIGN KEY (session_device_id) REFERENCES work_session_devices (id), CONSTRAINT fk_mold_lock_feedback_reporter FOREIGN KEY (reporter_phone) REFERENCES personnel (phone), CONSTRAINT fk_mold_lock_feedback_occupied FOREIGN KEY (occupied_phone) REFERENCES personnel (phone), CONSTRAINT fk_mold_lock_feedback_handler FOREIGN KEY (handled_by) REFERENCES personnel (phone) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci """ ) ) conn.execute( text( """ UPDATE work_session_devices d JOIN work_sessions s ON s.id = d.session_id SET d.released_at = COALESCE(s.end_at, s.updated_at, NOW()), d.release_reason = '历史非活动记录迁移释放占用' WHERE d.released_at IS NULL AND s.status NOT IN ('active', 'reporting') """ ) ) conn.execute( text( """ UPDATE work_session_devices d JOIN work_sessions s ON s.id = d.session_id JOIN ( SELECT session_id, MAX(sort_order) AS max_sort_order FROM work_session_devices GROUP BY session_id ) latest ON latest.session_id = d.session_id SET d.released_at = NOW(), d.release_reason = '历史切换记录迁移释放占用' WHERE d.released_at IS NULL AND s.status = 'active' AND d.sort_order < latest.max_sort_order """ ) ) print("mold lock columns and feedback table migrated") if __name__ == "__main__": main()