pipeline-opportunity/wwwroot/api/opp_mining_clusters.dspy

117 lines
5.1 KiB
Plaintext
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.

# opp_mining_clusters.dspy - 挖掘批次的类别排名(三级下钻第二级)
# 入参batch_id。可见性规则源 = opp_mining_flow.list_clusters含批次项目/org 校验)。
# 整行点击 → opp_mining_items.dspy 弹出类内需求明细第三级每条带来源URL
# 弹窗容器 id=opp_mine_clusters_pw与列表页下钻脚本约定一致
import json as _json
uid = await get_user()
if not uid:
return {"widgettype": "Message", "options": {"title": "未登录", "message": "请先登录"}}
batch_id = ((params_kw or {}).get("batch_id") or "").strip()
if not batch_id:
return {"widgettype": "Message", "options": {"title": "缺少参数", "message": "缺少 batch_id"}}
dbname = get_module_dbname('pipeline-opportunity')
session_id = (params_kw or {}).get('session_id', '') or ''
pipeline_id = (params_kw or {}).get('pipeline_id', '') or 'opportunity_general'
_cur_pid = ''
_uorg = ''
try:
from pipeline_service.workspace import get_session_project_id
async with DBPools().sqlorContext(dbname) as sor:
_cur_pid = await get_session_project_id(sor, uid, session_id, pipeline_id) or ''
_urecs = await sor.sqlExe("SELECT orgid FROM users WHERE id=${u}$", {"u": uid})
await sor.sqlExe("COMMIT", {})
if _urecs:
_uorg = str(getattr(_urecs[0], "orgid", "") or "")
except Exception:
pass
_ctx = {"project_id": _cur_pid, "user_id": uid, "org_id": _uorg,
"pipeline_id": pipeline_id, "session_id": session_id}
async with DBPools().sqlorContext(dbname) as sor:
from pipeline_opportunity.opp_mining_flow import list_clusters
_ok, _res = await list_clusters(sor, _ctx, batch_id)
await sor.sqlExe("COMMIT", {})
items_url = entire_url("/pipeline-opportunity/api/opp_mining_items.dspy")
rows = []
if not _ok:
rows.append({"widgettype": "Text", "options": {
"text": str(_res)[:200], "color": "#dc2626", "padding": "12px", "halign": "left"}})
else:
clusters = _res if isinstance(_res, list) else []
if not clusters:
rows.append({"widgettype": "Text", "options": {
"text": "该批次没有聚类结果(可能范围内无需求数据)",
"color": "#64748b", "padding": "12px", "halign": "left"}})
for c in clusters:
cid = str(c.get("id") or "")
name = str(c.get("name") or "未命名")
cnt = int(c.get("doc_count") or 0)
share = float(c.get("share") or 0) * 100
rank = int(c.get("heat_rank") or 0)
try:
ev = _json.loads(c.get("naming_evidence") or "{}")
except Exception:
ev = {}
samples = ev.get("samples") or []
ev_txt = ("命名依据:" + " / ".join(str(s)[:24] for s in samples[:3])) if samples else ""
by_txt = "(规则命名)" if ev.get("by") == "rule" else ""
q_extra = []
if session_id:
q_extra.append("session_id=" + session_id)
if pipeline_id:
q_extra.append("pipeline_id=" + pipeline_id)
qstr = ("&" + "&".join(q_extra)) if q_extra else ""
script = ("var old=bricks.getWidgetById('opp_mine_items_pw',bricks.app);"
"if(old&&old.destroy){old.destroy();}"
"var r=await fetch(" + _json.dumps(items_url) + "+'?cluster_id='+encodeURIComponent(" + _json.dumps(cid) + ")+" + _json.dumps(qstr) + ");"
"var d=await r.json();if(d){bricks.widgetBuild(d,bricks.app);}")
rows.append({
"widgettype": "HBox",
"options": {"width": "100%", "gap": "10px", "alignItems": "center",
"padding": "10px 14px", "border": "1px solid #e2e8f0",
"borderRadius": "8px", "margin": "0 0 8px 0", "bgcolor": "#ffffff",
"cursor": "pointer"},
"binds": [{"wid": "self", "event": "click", "actiontype": "script",
"target": "self", "script": script}],
"subwidgets": [
{"widgettype": "Text", "options": {"text": "#%d" % rank, "cfontsize": 0.85,
"color": "#94a3b8"}},
{"widgettype": "VBox", "options": {"gap": "2px"}, "subwidgets": [
{"widgettype": "Text", "options": {"text": name + by_txt, "cfontsize": 1.0,
"color": "#0f172a", "halign": "left"}},
{"widgettype": "Text", "options": {"text": ev_txt, "cfontsize": 0.72,
"color": "#94a3b8", "halign": "left",
"wrap": True}},
]},
{"widgettype": "Filler"},
{"widgettype": "Text", "options": {"text": "%d 条 %.1f%%" % (cnt, share),
"cfontsize": 0.85, "color": "#64748b"}},
{"widgettype": "Text", "options": {"text": "", "cfontsize": 1.1, "color": "#94a3b8"}},
]})
return {
"id": "opp_mine_clusters_pw",
"widgettype": "PopupWindow",
"options": {"title": "类别排名(批次 %s" % batch_id[:8], "width": "640px",
"height": "70%", "auto_open": True, "resizable": True},
"subwidgets": [{
"widgettype": "VBox",
"options": {"width": "100%", "height": "100%", "padding": "12px 16px",
"gap": "4px", "overflow": "auto"},
"subwidgets": [
{"widgettype": "Text", "options": {
"text": "点击任一类别,查看类内需求明细(每条带来源链接可查证)。",
"cfontsize": 0.78, "color": "#64748b", "halign": "left", "margin": "0 0 8px 0"}},
] + rows,
}],
}