Files
twoJob-demo/scripts/dbtool.py
T

138 lines
4.9 KiB
Python
Raw Normal View History

2026-09-03 15:35:23 +08:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
2号人事部 功能调研 —— SQLite 数据存取工具
用法:
python3 dbtool.py init 初始化数据库表结构
python3 dbtool.py add <json> 新增/更新一个功能节点(传入JSON对象)
python3 dbtool.py addmany <json_array> 批量新增/更新(传入JSON数组)
python3 dbtool.py setshot <node_key> <path> 设置某节点的截图路径
python3 dbtool.py get <node_key> 查询单个节点
python3 dbtool.py tree 以树形结构打印(JSON)
python3 dbtool.py stats 统计各层级节点数
节点字段:
node_key 唯一键(建议用 URL 或 path 组合, 用于去重更新)
parent_key 父节点的 node_key (顶层为空)
level 0=顶层模块 1=分组 2=菜单页 3=子页/Tab
name 功能名称
full_path 全路径名称(面包屑, 如 "人事 / 员工管理 / 员工花名册")
url 页面URL
description 释义(功能是做什么的)
understanding 我理解的信息(交互/字段/价值等)
screenshot_path 截图相对路径
sort_order 排序
keep 是否保留(供管理员勾选, 默认1=保留)
"""
import sqlite3, sys, json, os
DB_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "db", "research.db")
SCHEMA = """
CREATE TABLE IF NOT EXISTS features (
id INTEGER PRIMARY KEY AUTOINCREMENT,
node_key TEXT UNIQUE NOT NULL,
parent_key TEXT,
level INTEGER NOT NULL DEFAULT 0,
name TEXT NOT NULL,
full_path TEXT,
url TEXT,
description TEXT,
understanding TEXT,
screenshot_path TEXT,
sort_order INTEGER DEFAULT 0,
keep INTEGER DEFAULT 1,
created_at TEXT DEFAULT (datetime('now','localtime')),
updated_at TEXT DEFAULT (datetime('now','localtime'))
);
CREATE INDEX IF NOT EXISTS idx_parent ON features(parent_key);
CREATE INDEX IF NOT EXISTS idx_level ON features(level);
"""
FIELDS = ["node_key","parent_key","level","name","full_path","url",
"description","understanding","screenshot_path","sort_order","keep"]
def conn():
os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
c = sqlite3.connect(DB_PATH)
c.row_factory = sqlite3.Row
return c
def init():
c = conn()
c.executescript(SCHEMA)
c.commit(); c.close()
print("DB initialized at", DB_PATH)
def upsert(c, obj):
keys = [k for k in FIELDS if k in obj]
placeholders = ",".join(["?"]*len(keys))
cols = ",".join(keys)
updates = ",".join([f"{k}=excluded.{k}" for k in keys if k != "node_key"])
sql = f"INSERT INTO features ({cols}) VALUES ({placeholders}) " \
f"ON CONFLICT(node_key) DO UPDATE SET {updates}, updated_at=datetime('now','localtime')"
c.execute(sql, [obj[k] for k in keys])
def add(obj):
c = conn(); upsert(c, obj); c.commit(); c.close()
print("ok:", obj.get("node_key"))
def addmany(arr):
c = conn()
for obj in arr:
upsert(c, obj)
c.commit(); c.close()
print("ok addmany:", len(arr))
def setshot(node_key, path):
c = conn()
c.execute("UPDATE features SET screenshot_path=?, updated_at=datetime('now','localtime') WHERE node_key=?", (path, node_key))
c.commit(); n = c.total_changes; c.close()
print("updated" if n else "not found", node_key)
def get(node_key):
c = conn()
r = c.execute("SELECT * FROM features WHERE node_key=?", (node_key,)).fetchone()
c.close()
print(json.dumps(dict(r), ensure_ascii=False) if r else "null")
def stats():
c = conn()
rows = c.execute("SELECT level, COUNT(*) n FROM features GROUP BY level ORDER BY level").fetchall()
total = c.execute("SELECT COUNT(*) n FROM features").fetchone()["n"]
shots = c.execute("SELECT COUNT(*) n FROM features WHERE screenshot_path IS NOT NULL AND screenshot_path<>''").fetchone()["n"]
c.close()
for r in rows:
print(f"level {r['level']}: {r['n']}")
print(f"total: {total}, with_screenshot: {shots}")
def tree():
c = conn()
rows = [dict(r) for r in c.execute("SELECT * FROM features ORDER BY level, sort_order, id").fetchall()]
c.close()
by_parent = {}
for r in rows:
by_parent.setdefault(r["parent_key"] or "", []).append(r)
def build(pk):
out = []
for r in by_parent.get(pk, []):
node = {k: r[k] for k in ("node_key","name","level","url","description","understanding","screenshot_path","keep")}
node["children"] = build(r["node_key"])
out.append(node)
return out
print(json.dumps(build(""), ensure_ascii=False))
if __name__ == "__main__":
cmd = sys.argv[1] if len(sys.argv) > 1 else ""
if cmd == "init": init()
elif cmd == "add": add(json.loads(sys.argv[2]))
elif cmd == "addmany": addmany(json.loads(sys.argv[2]))
elif cmd == "setshot": setshot(sys.argv[2], sys.argv[3])
elif cmd == "get": get(sys.argv[2])
elif cmd == "stats": stats()
elif cmd == "tree": tree()
else:
print(__doc__)
sys.exit(1)