pipeline-opportunity/wwwroot/api/opp_mining_items.dspy

121 lines
5.3 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_items.dspy - 挖掘类别的类内需求明细(三级下钻第三级)
# 入参cluster_id。可见性经 opp_mining_flow.cluster_detail含批次项目/org 校验)。
# 每条带来源source_text 说明文字),整行点击 → opp_item_detail.dspy爬虫平台详情弹窗
# 快照 src_id 即爬虫平台 tenders.id直接复用既有详情通道
import json as _json
uid = await get_user()
if not uid:
return {"widgettype": "Message", "options": {"title": "未登录", "message": "请先登录"}}
cluster_id = ((params_kw or {}).get("cluster_id") or "").strip()
if not cluster_id:
return {"widgettype": "Message", "options": {"title": "缺少参数", "message": "缺少 cluster_id"}}
try:
limit = int((params_kw or {}).get("limit") or 50)
except (TypeError, ValueError):
limit = 50
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 cluster_detail
from pipeline_opportunity.opp_common import source_text
_ok, _res = await cluster_detail(sor, _ctx, cluster_id, limit=limit)
await sor.sqlExe("COMMIT", {})
detail_url = entire_url("/pipeline-opportunity/api/opp_item_detail.dspy")
rows = []
if not _ok:
rows.append({"widgettype": "Text", "options": {
"text": str(_res)[:200], "color": "#dc2626", "padding": "12px", "halign": "left"}})
cl_name, cl_cnt = "", 0
else:
cl = _res.get("cluster") or {}
cl_name = str(cl.get("name") or "")
cl_cnt = int(cl.get("doc_count") or 0)
items = _res.get("samples") or []
if not items:
rows.append({"widgettype": "Text", "options": {
"text": "该类别暂无明细", "color": "#64748b", "padding": "12px", "halign": "left"}})
for it in items:
src_id = str(it.get("src_id") or "")
title = str(it.get("title") or "")
budget = it.get("budget_wan") or 0
url = str(it.get("url") or "")
src_name = source_text(str(it.get("source") or ""), "")
meta = "%s %s 来源:%s" % (
str(it.get("publish_time") or "")[:10],
(("预算 %.2f 万" % float(budget)) if budget else "预算面议"),
src_name)
row_subs = [
{"widgettype": "Text", "options": {"text": title, "cfontsize": 0.95,
"color": "#0f172a", "halign": "left", "wrap": True}},
{"widgettype": "HBox", "options": {"width": "100%", "gap": "10px", "alignItems": "center"},
"subwidgets": [
{"widgettype": "Text", "options": {"text": meta, "cfontsize": 0.75,
"color": "#94a3b8", "halign": "left", "wrap": True}},
{"widgettype": "Filler"},
{"widgettype": "Text", "options": {"text": "", "cfontsize": 1.0, "color": "#94a3b8"}},
]},
]
row_opts = {"width": "100%", "padding": "8px 12px", "gap": "4px",
"border": "1px solid #e2e8f0", "borderRadius": "8px",
"margin": "0 0 6px 0", "bgcolor": "#ffffff"}
if src_id:
row_opts["cursor"] = "pointer"
script = ("var old=bricks.getWidgetById('opp_item_detail_pw',bricks.app);"
"if(old&&old.destroy){old.destroy();}"
"var rp=await fetch(" + _json.dumps(detail_url) + "+'?id='+encodeURIComponent(" + _json.dumps(src_id) + "));"
"var d=await rp.json();if(d){bricks.widgetBuild(d,bricks.app);}")
rows.append({"widgettype": "VBox", "options": row_opts,
"binds": [{"wid": "self", "event": "click", "actiontype": "script",
"target": "self", "script": script}],
"subwidgets": row_subs})
elif url:
row_opts["cursor"] = "pointer"
script = "window.open(" + _json.dumps(url) + ",'_blank');"
rows.append({"widgettype": "VBox", "options": row_opts,
"binds": [{"wid": "self", "event": "click", "actiontype": "script",
"target": "self", "script": script}],
"subwidgets": row_subs})
else:
rows.append({"widgettype": "VBox", "options": row_opts, "subwidgets": row_subs})
return {
"widgettype": "PopupWindow",
"id": "opp_mine_items_pw",
"options": {"title": "类内需求明细:%s%d 条,显示前 %d" % (cl_name, cl_cnt, limit),
"width": "76%", "height": "80%", "auto_open": True, "resizable": True},
"subwidgets": [{
"widgettype": "VBox",
"options": {"css": "filler", "width": "100%", "height": "100%",
"padding": "12px 16px", "gap": "0px", "overflow": "auto"},
"subwidgets": [
{"widgettype": "Text", "options": {
"text": "点击任一条目弹出需求详情(数据来自数据爬取平台快照,每条标注来源平台)。",
"cfontsize": 0.78, "color": "#64748b", "halign": "left", "margin": "0 0 8px 0"}},
] + rows,
}],
}