"""SQLite 连接与幂等初始化(职称评审核验助手)。 业务表 2 张: - threshold_rules(评审门槛库,可编辑) - verify_cases(核验案例,只读,核验自动写入) 表间禁止 SQLite 外键,仅存业务 id(见 references/SCHEMA.md)。 """ from __future__ import annotations import sqlite3 from db.display_metadata import ( init_display_metadata, seed_column_metadata_batch, upsert_table_metadata, ) from db.seed_data import seed_all from db.timestamp_columns import init_updated_at_trigger from util.runtime_paths import get_db_path def get_conn() -> sqlite3.Connection: return sqlite3.connect(get_db_path()) _THRESHOLD_RULES_DDL = """ CREATE TABLE IF NOT EXISTS threshold_rules ( id INTEGER PRIMARY KEY AUTOINCREMENT, rank TEXT NOT NULL, metric_key TEXT NOT NULL, metric_name TEXT NOT NULL, min_value REAL NOT NULL, unit TEXT, basis_doc TEXT, clause TEXT, created_at INTEGER NOT NULL DEFAULT (unixepoch()), updated_at INTEGER NOT NULL DEFAULT (unixepoch()), UNIQUE (rank, metric_key) ) """ _VERIFY_CASES_DDL = """ CREATE TABLE IF NOT EXISTS verify_cases ( id INTEGER PRIMARY KEY AUTOINCREMENT, batch_no TEXT NOT NULL, teacher_name TEXT, department TEXT, apply_rank TEXT, metrics_json TEXT, verdict TEXT NOT NULL, matrix_json TEXT, report_file TEXT, created_at INTEGER NOT NULL DEFAULT (unixepoch()) ) """ _VERIFY_CASES_INDEX = """ CREATE INDEX IF NOT EXISTS idx_verify_cases_batch ON verify_cases(batch_no) """ _TS_COLUMN_NAMES = {"created_at", "updated_at"} def _col(column_name: str, display_name: str, description: str, **extra: object) -> dict[str, object]: base: dict[str, object] = { "column_name": column_name, "display_name": display_name, "description": description, "visible": 1, "searchable": 0, "editable": 0, } base.update(extra) if column_name in _TS_COLUMN_NAMES: base["display_type"] = "datetime_unix_seconds" return base _THRESHOLD_RULES_COLUMNS: tuple[dict[str, object], ...] = ( _col("id", "编号", "主键", searchable=1), _col("rank", "申报级别", "副教授 / 教授。", searchable=1), _col("metric_key", "指标键", "指标唯一键(presiding_provincial 等)。", searchable=1), _col("metric_name", "指标名称", "如 主持省部级项目。", searchable=1, editable=1), _col("min_value", "最低要求", "刚性门槛数值。", searchable=1, editable=1, display_type="number"), _col("unit", "单位", "项/篇/课时/年 等。", editable=1), _col("basis_doc", "依据文件", "如《专业技术职务评聘办法》。", searchable=1, editable=1), _col("clause", "条款", "门槛出处条款号。", editable=1), _col("created_at", "创建时间", "记录创建时间(Unix 秒级,自动生成)。"), _col("updated_at", "更新时间", "记录最后更新时间(Unix 秒级,自动维护)。"), ) _VERIFY_CASES_COLUMNS: tuple[dict[str, object], ...] = ( _col("id", "案例编号", "主键,核验记录编号。", searchable=1), _col("batch_no", "核验批次号", "同一次核验请求的批次号。", searchable=1), _col("teacher_name", "教师姓名", "被核验教师。", searchable=1), _col("department", "所属学院", "教师所属学院。", searchable=1), _col("apply_rank", "申报级别", "副教授 / 教授。", searchable=1), _col("metrics_json", "申报指标", "教师实有指标(JSON,默认隐藏)。", visible=0, display_type="textarea"), _col( "verdict", "核验结论", "安全(形式审查通过)/ 边缘(建议补充)/ 硬伤(暂缓提交)。", searchable=1, options_json='[{"value":"安全","label":"🟢 安全"},{"value":"边缘","label":"🟡 边缘"},{"value":"硬伤","label":"🔴 硬伤"}]', ), _col("matrix_json", "达标矩阵", "逐项达标矩阵(JSON)。", visible=0, display_type="textarea"), _col("report_file", "报告文件", "《核验报告》HTML 文件路径。", visible=0), _col("created_at", "创建时间", "记录创建时间(Unix 秒级,自动生成)。"), ) def _init_threshold_rules_metadata(cursor) -> None: cursor.execute(_THRESHOLD_RULES_DDL) init_updated_at_trigger(cursor, "threshold_rules") upsert_table_metadata( cursor, table_name="threshold_rules", display_name="评审门槛库", description="各级别职称申报的刚性门槛(数值须以人事处最新文件为准)。", grid_help="按 申报级别+指标键 唯一;行内可编辑最低要求与依据条款。", visible=1, readonly=0, ) seed_column_metadata_batch( cursor, table_name="threshold_rules", columns=_THRESHOLD_RULES_COLUMNS, valid_column_names=[str(c["column_name"]) for c in _THRESHOLD_RULES_COLUMNS], ) def _init_verify_cases_metadata(cursor) -> None: cursor.execute(_VERIFY_CASES_DDL) cursor.execute(_VERIFY_CASES_INDEX) upsert_table_metadata( cursor, table_name="verify_cases", display_name="核验案例", description="每次核验的达标矩阵与三色结论;可重建《核验报告》。", grid_help="🔴硬伤=存在不达门槛项;🟡边缘=达标但余量不足10%;🟢安全=全部超标准10%以上。", visible=1, readonly=1, default_sort_json='[{"column":"id","direction":"desc"}]', default_visible_columns_json='["id","teacher_name","department","apply_rank","verdict","created_at"]', ) seed_column_metadata_batch( cursor, table_name="verify_cases", columns=_VERIFY_CASES_COLUMNS, valid_column_names=[str(c["column_name"]) for c in _VERIFY_CASES_COLUMNS], ) def init_db() -> dict[str, int]: """幂等创建/迁移本地 SQLite、数据管理元数据与门槛种子。""" conn = get_conn() try: cur = conn.cursor() init_display_metadata(cur) _init_threshold_rules_metadata(cur) _init_verify_cases_metadata(cur) seeded = seed_all(cur) conn.commit() return seeded finally: conn.close()