Files
verify-promotion-metric-def…/scripts/db/connection.py
chenfuqiang 04026d0372
All checks were successful
技能自动化发布 / release (push) Successful in 7s
feat: 职称评审核验助手首版 v1.0.1(verify-promotion-metric-default)
2026-09-13 16:05:20 +08:00

170 lines
6.2 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.
"""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()