91 lines
4.2 KiB
Plaintext
91 lines
4.2 KiB
Plaintext
# my_pipelines.dspy - 当前用户可用产线列表 → ChipBar 数据(手机端「产线」Tab 胶囊条)
|
||
# 口径(2026-09-07 用户定夺):客户只显示购买过且未到期的产线;
|
||
# 平台侧(owner./reseller. 角色)显示全部 published 产线。
|
||
# 数据链:product_subscription(status='1', end_date>=今天) × product(product_type='pipeline',
|
||
# resource_ref_id=pipelines.id) × pipelines(status='published')。
|
||
|
||
import json as _json
|
||
|
||
uid = await get_user()
|
||
if not uid:
|
||
return _json.dumps({"items": [], "error": "未登录"}, ensure_ascii=False)
|
||
|
||
orgid = await get_userorgid()
|
||
dbname = get_module_dbname('pipeline_core')
|
||
|
||
# mode=full(桌面侧边栏/管理场景):不过滤订阅,返回全部 published 产线;
|
||
# 默认(手机端 ChipBar):客户只见已购未到期产线(2026-09-07 用户定夺)
|
||
_mode = ((params_kw or {}).get('mode') or '').strip()
|
||
|
||
# fmt=more(底部 TabBar「更多」菜单):返回 MobileSheet 项格式
|
||
# [{name,label,icon,desc,url}],url 直达该产线会话页(2026-09-08)
|
||
_fmt = ((params_kw or {}).get('fmt') or '').strip()
|
||
|
||
items = []
|
||
try:
|
||
# 平台侧角色(owner./reseller.)看全部 published 产线;客户只看已购未到期。
|
||
# get_user_roles 由 rbac.init 注册到 ServerEnv,dspy run_ns 会带入;
|
||
# 探测失败/不可用时默认按客户处理(只显示已购,安全侧,不放大可见面)。
|
||
is_ops = _mode == 'full'
|
||
if not is_ops:
|
||
try:
|
||
roles = await get_user_roles(uid)
|
||
for r in (roles or []):
|
||
rs = str(r)
|
||
if rs.startswith('owner.') or rs.startswith('reseller.'):
|
||
is_ops = True
|
||
break
|
||
except Exception:
|
||
is_ops = False
|
||
|
||
async with DBPools().sqlorContext(dbname) as sor:
|
||
if is_ops:
|
||
recs = await sor.sqlExe(
|
||
"SELECT id, name FROM pipelines WHERE status='published' ORDER BY id", {})
|
||
await sor.sqlExe("COMMIT", {})
|
||
ids = [(getattr(r, 'id', ''), getattr(r, 'name', '')) for r in (recs or [])]
|
||
else:
|
||
srecs = await sor.sqlExe(
|
||
"SELECT DISTINCT pr.resource_ref_id AS rid FROM product_subscription ps"
|
||
" JOIN product pr ON ps.product_id = pr.id"
|
||
" WHERE ps.user_org_id=${org}$ AND ps.status='1'"
|
||
" AND ps.end_date >= CURDATE()"
|
||
" AND pr.product_type='pipeline'", {"org": orgid})
|
||
await sor.sqlExe("COMMIT", {})
|
||
rids = []
|
||
for r in (srecs or []):
|
||
v = getattr(r, 'rid', '')
|
||
if v and v not in rids:
|
||
rids.append(v)
|
||
ids = []
|
||
if rids:
|
||
# sqlor IN 列表必须展开占位符(传 list 会崩)
|
||
ph = {}
|
||
marks = []
|
||
for i, rid in enumerate(rids):
|
||
k = 'k%d' % i
|
||
ph[k] = rid
|
||
marks.append('${%s}$' % k)
|
||
prec = await sor.sqlExe(
|
||
"SELECT id, name FROM pipelines WHERE status='published'"
|
||
" AND id IN (" + ','.join(marks) + ") ORDER BY id", ph)
|
||
await sor.sqlExe("COMMIT", {})
|
||
ids = [(getattr(r, 'id', ''), getattr(r, 'name', '')) for r in (prec or [])]
|
||
|
||
for pid, pname in ids:
|
||
if _fmt == 'more':
|
||
# 底部 TabBar「更多」菜单项(2026-09-08):点击 → 内容区直达该产线
|
||
# 会话页(embed=1:隐藏胶囊条/门禁,锁定产线,会话区最大化)。
|
||
# url 不预 urlencode(前端 url_parse 会再编码一次,双重编码坑)
|
||
items.append({"name": "m_pl_" + pid, "label": pname or pid,
|
||
"icon": "⚡", "desc": "已购产线",
|
||
"url": entire_url("/pipeline_core/mobile_agent.ui")
|
||
+ "?pipeline_id=" + pid + "&embed=1"})
|
||
else:
|
||
items.append({"id": pid, "pipeline_id": pid,
|
||
"name": pname or pid, "session_id": "m_" + pid})
|
||
except Exception:
|
||
items = []
|
||
|
||
return _json.dumps({"items": items}, ensure_ascii=False)
|