This commit is contained in:
BBIT-Kai
2026-07-16 09:28:57 +08:00
parent cb9a411c55
commit 7be72a50ad
13 changed files with 3383 additions and 0 deletions
+134
View File
@@ -0,0 +1,134 @@
from typing import Any
from psycopg.types.json import Jsonb
from config.pgDb import pg_pool
def list_cube_report_states(user_id: str) -> dict[str, dict[str, Any]]:
with pg_pool.getConn() as conn:
with conn.cursor() as cur:
cur.execute(
"""
SELECT dify_conversation_id, current_cube, limit_source,
response_message, updated_at
FROM ai_cube_report_states
WHERE created_by = %s
""",
(user_id,),
)
return {
str(row[0]): {
"query": row[1],
"limitSource": row[2],
"message": row[3],
"updatedAt": row[4].isoformat() if row[4] else None,
}
for row in cur.fetchall()
}
def get_cube_report_state(
conversation_id: str, user_id: str
) -> dict[str, Any] | None:
with pg_pool.getConn() as conn:
with conn.cursor() as cur:
cur.execute(
"""
SELECT title, tenant_id, tenant_name, allow_global,
current_cube, limit_source, response_message,
created_at, updated_at
FROM ai_cube_report_states
WHERE dify_conversation_id = %s AND created_by = %s
""",
(conversation_id, user_id),
)
row = cur.fetchone()
if not row:
return None
return {
"conversationId": conversation_id,
"title": row[0],
"tenantId": str(row[1]) if row[1] is not None else None,
"tenantName": row[2],
"allowGlobal": row[3],
"query": row[4],
"limitSource": row[5],
"message": row[6],
"createdAt": row[7].isoformat() if row[7] else None,
"updatedAt": row[8].isoformat() if row[8] else None,
}
def upsert_cube_report_state(
*,
conversation_id: str,
user_id: str,
title: str,
tenant_id: str | None,
tenant_name: str,
allow_global: bool,
query: dict[str, Any],
limit_source: str,
response_message: str,
) -> None:
normalized_source = "user" if limit_source == "user" else "system"
with pg_pool.getConn() as conn:
with conn.cursor() as cur:
cur.execute(
"""
INSERT INTO ai_cube_report_states (
dify_conversation_id, created_by, title, tenant_id,
tenant_name, allow_global, current_cube, limit_source,
response_message, created_at, updated_at
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW())
ON CONFLICT (dify_conversation_id) DO UPDATE SET
title = EXCLUDED.title,
tenant_id = EXCLUDED.tenant_id,
tenant_name = EXCLUDED.tenant_name,
allow_global = EXCLUDED.allow_global,
current_cube = EXCLUDED.current_cube,
limit_source = EXCLUDED.limit_source,
response_message = EXCLUDED.response_message,
updated_at = NOW()
WHERE ai_cube_report_states.created_by = EXCLUDED.created_by
""",
(
conversation_id,
user_id,
title[:200] or "新数据对话",
tenant_id,
tenant_name[:200],
allow_global,
Jsonb(query),
normalized_source,
response_message,
),
)
def rename_cube_report_state(
conversation_id: str, user_id: str, title: str
) -> None:
with pg_pool.getConn() as conn:
with conn.cursor() as cur:
cur.execute(
"""
UPDATE ai_cube_report_states
SET title = %s, updated_at = NOW()
WHERE dify_conversation_id = %s AND created_by = %s
""",
(title[:200], conversation_id, user_id),
)
def delete_cube_report_state(conversation_id: str, user_id: str) -> None:
with pg_pool.getConn() as conn:
with conn.cursor() as cur:
cur.execute(
"""
DELETE FROM ai_cube_report_states
WHERE dify_conversation_id = %s AND created_by = %s
""",
(conversation_id, user_id),
)
+45
View File
@@ -14,6 +14,21 @@ def executeSQL(sql: str):
return [dict(row._mapping) for row in result]
def execute_parameterized_sql(sql: str, params: dict | None = None):
"""执行参数化只读 SQL,返回列名和字典行。"""
with mssql_pool.getConn() as conn:
result = conn.execute(text(sql), params or {})
columns = list(result.keys())
rows = [dict(row._mapping) for row in result]
return columns, rows
def execute_parameterized_scalar(sql: str, params: dict | None = None):
with mssql_pool.getConn() as conn:
result = conn.execute(text(sql), params or {})
return result.scalar()
def get_company_list(user_id: str):
# 1️⃣ 从 PostgreSQL 获取 tenant_id
with pg_pool.getConn() as pg_conn:
@@ -35,3 +50,33 @@ def get_company_list(user_id: str):
with mssql_pool.getConn() as mssql_conn:
result = mssql_conn.execute(query, params)
return [{"id": str(row[0]), "name": row[1]} for row in result.fetchall()]
def get_user_company_scope(user_id: str):
"""返回数据助手使用的租户范围;用户不存在时绝不能按全局用户处理。"""
with pg_pool.getConn() as pg_conn:
with pg_conn.cursor() as cur:
cur.execute(
"SELECT bbit_tenant_id FROM sys_users WHERE id = %s", (user_id,)
)
row = cur.fetchone()
if not row:
return {"canGlobal": False, "companies": []}
tenant_id = row[0]
if tenant_id:
query = text("SELECT Id, Name FROM dbo.POC_TENANTS WHERE Id = :tenant_id")
params = {"tenant_id": tenant_id}
can_global = False
else:
query = text("SELECT Id, Name FROM dbo.POC_TENANTS ORDER BY Name")
params = {}
can_global = True
with mssql_pool.getConn() as mssql_conn:
result = mssql_conn.execute(query, params)
companies = [
{"id": str(item[0]), "name": item[1]} for item in result.fetchall()
]
return {"canGlobal": can_global, "companies": companies}