pipeline-opportunity/wwwroot/api/opp_references_popup.dspy

152 lines
7.0 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_references_popup.dspy - 数据参考(references):主题列表(agent_menu_open 弹窗内嵌内容)
# 点主题「查看分项」→ 对应分项列表(每条带来源,点击新窗口查证):
# 招标主题 → opp_references_items.dspy;国内众包需求主题 → opp_demand_items.dspy;
# 海外众包需求主题 → opp_overseas_items.dspy
import json as _json
uid = await get_user()
if not uid:
return {"widgettype": "Text", "options": {"text": "请先登录", "color": "#dc2626", "padding": "12px"}}
dbname = get_module_dbname('pipeline-opportunity')
items_url = entire_url("/pipeline-opportunity/api/opp_references_items.dspy")
demand_items_url = entire_url("/pipeline-opportunity/api/opp_demand_items.dspy")
overseas_items_url = entire_url("/pipeline-opportunity/api/opp_overseas_items.dspy")
async with DBPools().sqlorContext(dbname) as sor:
from pipeline_opportunity.opp_data_capability import hot_software, hot_demands, hot_overseas
ok, res = await hot_software(sor, days=30, top=10)
await sor.sqlExe("COMMIT", {})
ok_dm, res_dm = await hot_demands(sor, days=30, top=10)
await sor.sqlExe("COMMIT", {})
ok_ov, res_ov = await hot_overseas(sor, days=30, top=10)
await sor.sqlExe("COMMIT", {})
rows = []
if not ok:
rows.append({"widgettype": "Text", "options": {
"text": "数据爬取平台暂不可用:" + str(res)[:200],
"color": "#dc2626", "padding": "12px", "halign": "left"}})
else:
ranking = res.get("ranking") or []
if not ranking:
rows.append({"widgettype": "Text", "options": {
"text": "近30天暂无招标数据", "color": "#64748b", "padding": "12px", "halign": "left"}})
for i, r in enumerate(ranking):
cat = str(r.get("category", ""))
cnt = r.get("tender_count", 0)
budget = r.get("total_budget_wan", 0)
script = ("var old=bricks.getWidgetById('opp_refs_items_pw',bricks.app);"
"if(old&&old.destroy){old.destroy();}"
"var rp=await fetch(" + _json.dumps(items_url) + "+'?category='+encodeURIComponent(" + _json.dumps(cat) + "));"
"var d=await rp.json();"
"if(d){bricks.widgetBuild(d,bricks.app);}")
rows.append({
"widgettype": "HBox",
"options": {"width": "100%", "gap": "10px", "alignItems": "center",
"padding": "8px 14px", "border": "1px solid #e2e8f0",
"borderRadius": "8px", "margin": "0 0 8px 0", "bgcolor": "#ffffff"},
"subwidgets": [
{"widgettype": "Text", "options": {"text": cat, "cfontsize": 1.0,
"color": "#0f172a", "halign": "left"}},
{"widgettype": "Filler"},
{"widgettype": "Text", "options": {"text": "%d 条" % cnt,
"cfontsize": 0.85, "color": "#64748b"}},
{"widgettype": "Text", "options": {"text": "预算 %s 万" % ("{:,.0f}".format(budget) if budget else "—"),
"cfontsize": 0.85, "color": "#64748b"}},
{"widgettype": "Button", "options": {"label": "查看分项", "css": "small"},
"binds": [{"wid": "self", "event": "click", "actiontype": "script",
"target": "self", "script": script}]}
]
})
# ── 国内众包需求板块(猪八戒/一品威客)──
dm_rows = []
if ok_dm:
dm_ranking = res_dm.get("ranking") or []
if dm_ranking:
dm_rows.append({"widgettype": "Text", "options": {
"text": "国内众包软件需求(猪八戒/一品威客,近30天)",
"cfontsize": 0.95, "color": "#0f172a", "halign": "left",
"margin": "14px 0 6px 0", "padding": "6px 0 0 0",
"border": "1px solid #f1f5f9", "borderRadius": "6px", "bgcolor": "#f8fafc"}})
for r in dm_ranking:
cat = str(r.get("category", ""))
cnt = r.get("tender_count", 0)
budget = r.get("total_budget_wan", 0)
script = ("var old=bricks.getWidgetById('opp_demand_items_pw',bricks.app);"
"if(old&&old.destroy){old.destroy();}"
"var rp=await fetch(" + _json.dumps(demand_items_url) + "+'?category='+encodeURIComponent(" + _json.dumps(cat) + "));"
"var d=await rp.json();"
"if(d){bricks.widgetBuild(d,bricks.app);}")
dm_rows.append({
"widgettype": "HBox",
"options": {"width": "100%", "gap": "10px", "alignItems": "center",
"padding": "8px 14px", "border": "1px solid #e2e8f0",
"borderRadius": "8px", "margin": "0 0 8px 0", "bgcolor": "#ffffff"},
"subwidgets": [
{"widgettype": "Text", "options": {"text": cat, "cfontsize": 1.0,
"color": "#0f172a", "halign": "left"}},
{"widgettype": "Filler"},
{"widgettype": "Text", "options": {"text": "%d 条" % cnt,
"cfontsize": 0.85, "color": "#64748b"}},
{"widgettype": "Text", "options": {"text": "预算 %s 万" % ("{:,.0f}".format(budget) if budget else "—"),
"cfontsize": 0.85, "color": "#64748b"}},
{"widgettype": "Button", "options": {"label": "查看分项", "css": "small"},
"binds": [{"wid": "self", "event": "click", "actiontype": "script",
"target": "self", "script": script}]}
]
})
# ── 海外众包需求板块(Freelancer.com / PeoplePerHour)──
ov_rows = []
if ok_ov:
ov_ranking = res_ov.get("ranking") or []
if ov_ranking:
ov_rows.append({"widgettype": "Text", "options": {
"text": "海外众包软件需求(Freelancer.com / PeoplePerHour,近30天)",
"cfontsize": 0.95, "color": "#0f172a", "halign": "left",
"margin": "14px 0 6px 0", "padding": "6px 0 0 0",
"border": "1px solid #f1f5f9", "borderRadius": "6px", "bgcolor": "#f8fafc"}})
for r in ov_ranking:
cat = str(r.get("category", ""))
cnt = r.get("tender_count", 0)
by_src = r.get("by_source") or {}
src_txt = " / ".join("%s:%d" % (k, v) for k, v in by_src.items())
script = ("var old=bricks.getWidgetById('opp_overseas_items_pw',bricks.app);"
"if(old&&old.destroy){old.destroy();}"
"var rp=await fetch(" + _json.dumps(overseas_items_url) + "+'?category='+encodeURIComponent(" + _json.dumps(cat) + "));"
"var d=await rp.json();"
"if(d){bricks.widgetBuild(d,bricks.app);}")
ov_rows.append({
"widgettype": "HBox",
"options": {"width": "100%", "gap": "10px", "alignItems": "center",
"padding": "8px 14px", "border": "1px solid #e2e8f0",
"borderRadius": "8px", "margin": "0 0 8px 0", "bgcolor": "#ffffff"},
"subwidgets": [
{"widgettype": "Text", "options": {"text": cat, "cfontsize": 1.0,
"color": "#0f172a", "halign": "left"}},
{"widgettype": "Filler"},
{"widgettype": "Text", "options": {"text": "%d 条" % cnt,
"cfontsize": 0.85, "color": "#64748b"}},
{"widgettype": "Text", "options": {"text": src_txt,
"cfontsize": 0.75, "color": "#94a3b8"}},
{"widgettype": "Button", "options": {"label": "查看分项", "css": "small"},
"binds": [{"wid": "self", "event": "click", "actiontype": "script",
"target": "self", "script": script}]}
]
})
return {
"widgettype": "VBox",
"options": {"css": "filler", "width": "100%", "height": "100%", "padding": "12px 16px",
"gap": "6px", "overflow": "auto"},
"subwidgets": [
{"widgettype": "Text", "options": {
"text": "点击「查看分项」列出该主题的全部数据项;每条数据项带来源链接(公告原文/需求详情/来源页),可逐条点开查证。",
"cfontsize": 0.8, "color": "#64748b", "halign": "left", "margin": "0 0 8px 0"}}
] + rows + dm_rows + ov_rows
}