feat(mobile): 手机端「更多」产线入口+功能按钮收缩(2026-09-08用户要求:给会话留最大空间)——my_pipelines.dspy 加 fmt=more 返回 MobileSheet 项[{name,label,icon,desc,url}],url 直达 mobile_agent.ui?pipeline_id=X&embed=1 单产线会话页(已购即出现在底部「更多」,无需改 index.ui);mobile_agent.ui 加 embed 分支(隐藏 ChipBar 胶囊条+门禁遮罩,锁定产线,AgentIO 自带 pipeline_id/session_id=m_<pid>,会话区最大化,服务端 agent_chat 硬门禁兜底);agent_menus.dspy 按 _is_mobile 端形态分流(桌面一排 Button 原样不变,手机收缩为单个「⋯ 功能」Button→MobileSheet 竖排,项 popup:true 点击走 agent_menu_open/workspace_popup 的 PopupWindow 自开链路,与桌面完全一致)
This commit is contained in:
parent
2cfbc55dc3
commit
5ad85f1b60
@ -54,75 +54,93 @@ try:
|
||||
except Exception:
|
||||
menus = []
|
||||
|
||||
# 3. 构建菜单按钮(actiontype=urlwidget 打开通用弹窗 agent_menu_open,控制弹窗大小)
|
||||
# 3. 构建功能入口(actiontype=urlwidget 打开通用弹窗 agent_menu_open,控制弹窗大小)
|
||||
# 注意:这里不预先 urlencode 查询参数。前端 bricks_fetch 的 url_parse 会把 url 里的
|
||||
# 查询参数提取后再 encodeURIComponent 编码一次,若此处已 urlencode 会导致双重编码
|
||||
# (title 的 emoji/中文会变成 %F0%9F... 明文显示)。
|
||||
#
|
||||
# 「需要项目」判断在【点击时】由 agent_menu_open 服务端做(传 require_project/session_id/pipeline_id):
|
||||
# 渲染时固化判断是老 bug——页面加载时还没切项目 → 按钮写死报错脚本,之后切了项目仍报错。
|
||||
#
|
||||
# 端形态(2026-09-08 用户要求:产线上方的按钮收缩为一个菜单项,给会话留最大空间):
|
||||
# 桌面:一排 Button(原样)
|
||||
# 手机(jsoncall 自动带 _is_mobile=1):单个「⋯ 功能」Button → 点击弹
|
||||
# MobileSheet 竖向菜单,项点击走同一 open_url(popup:true,agent_menu_open
|
||||
# 返回 PopupWindow 自开,与桌面链路完全一致)
|
||||
|
||||
buttons = []
|
||||
_is_mobile = str((params_kw or {}).get('_is_mobile', '') or '') == '1'
|
||||
|
||||
# 通用会话(pipeline_id=_generic):只给"工作空间"按钮,锁用户专属目录
|
||||
actions = [] # [{label, url}] 统一收集,最后按端形态渲染
|
||||
|
||||
# 通用会话(pipeline_id=_generic):只给"工作空间"入口,锁用户专属目录
|
||||
if pipeline_id == '_generic':
|
||||
buttons.append({
|
||||
"widgettype": "Button",
|
||||
"options": {"label": "🗂 工作空间", "css": "small", "id": "menu_btn_ws_generic"},
|
||||
"binds": [{
|
||||
"wid": "self", "event": "click", "actiontype": "urlwidget",
|
||||
"target": "self",
|
||||
"options": {"url": entire_url("/pipeline-sdlc/api/workspace_popup.dspy")
|
||||
+ "?pipeline_id=_generic"},
|
||||
}],
|
||||
actions.append({
|
||||
"label": "🗂 工作空间",
|
||||
"url": entire_url("/pipeline-sdlc/api/workspace_popup.dspy")
|
||||
+ "?pipeline_id=_generic",
|
||||
})
|
||||
else:
|
||||
# 固定「工作空间」入口(通用能力,所有 agent 都有;依赖当前项目)
|
||||
# 带产线参数:入口产线与会话项目跨产线时视为无项目(产线隔离,弹窗端点自身在点击时判断)
|
||||
_ws_url = entire_url("/pipeline-sdlc/api/workspace_popup.dspy")
|
||||
_ws_q = []
|
||||
if session_id:
|
||||
_ws_q.append("session_id=" + session_id)
|
||||
if pipeline_id:
|
||||
_ws_q.append("pipeline_id=" + pipeline_id)
|
||||
if _ws_q:
|
||||
_ws_url += "?" + "&".join(_ws_q)
|
||||
actions.append({"label": "🗂 工作空间", "url": _ws_url})
|
||||
|
||||
for i, m in enumerate(menus):
|
||||
label = str(m.get("label", "") or "")
|
||||
url = str(m.get("url", "") or "")
|
||||
if not url:
|
||||
continue
|
||||
require_project = bool(m.get("require_project", False))
|
||||
width = str(m.get("width", "85%") or "85%")
|
||||
height = str(m.get("height", "80%") or "80%")
|
||||
open_url = (entire_url("/pipeline_core/api/agent_menu_open.dspy")
|
||||
+ "?url=" + url + "&title=" + label
|
||||
+ "&width=" + width + "&height=" + height
|
||||
+ ("&require_project=1" if require_project else ""))
|
||||
if session_id:
|
||||
open_url += "&session_id=" + session_id
|
||||
if pipeline_id:
|
||||
open_url += "&pipeline_id=" + pipeline_id
|
||||
actions.append({"label": label, "url": open_url})
|
||||
|
||||
if _is_mobile:
|
||||
# 手机端:收缩为单个「⋯ 功能」按钮 → MobileSheet 竖向菜单。
|
||||
# items 内联进脚本(JSON 字面量);popup:true → 点击 widgetBuild urlwidget,
|
||||
# 服务端返回 PopupWindow 自开(agent_menu_open / workspace_popup 同链路)。
|
||||
_items = [{"name": "act_%d" % i, "label": a["label"], "url": a["url"], "popup": True}
|
||||
for i, a in enumerate(actions)]
|
||||
_script = (
|
||||
"var its=" + _json.dumps(_items, ensure_ascii=False) + ";"
|
||||
"var sh=new bricks.MobileSheet({title:'功能',items:its});sh.open();"
|
||||
)
|
||||
return _json.dumps({
|
||||
"widgettype": "HBox",
|
||||
"options": {"width": "100%", "padding": "0 12px 8px 12px", "gap": "8px", "alignItems": "center"},
|
||||
"subwidgets": buttons,
|
||||
"options": {"width": "100%", "padding": "0 12px 6px 12px", "gap": "8px", "alignItems": "center"},
|
||||
"subwidgets": [{
|
||||
"widgettype": "Button",
|
||||
"options": {"label": "⋯ 功能", "css": "small", "id": "menu_btn_mobile_more"},
|
||||
"binds": [{
|
||||
"wid": "self", "event": "click", "actiontype": "script",
|
||||
"target": "self", "script": _script,
|
||||
}],
|
||||
}],
|
||||
}, ensure_ascii=False)
|
||||
|
||||
# 固定「工作空间」按钮(通用能力,所有 agent 都有;依赖当前项目)
|
||||
# 带产线参数:入口产线与会话项目跨产线时视为无项目(产线隔离,弹窗端点自身在点击时判断)
|
||||
_ws_url = entire_url("/pipeline-sdlc/api/workspace_popup.dspy")
|
||||
_ws_q = []
|
||||
if session_id:
|
||||
_ws_q.append("session_id=" + session_id)
|
||||
if pipeline_id:
|
||||
_ws_q.append("pipeline_id=" + pipeline_id)
|
||||
if _ws_q:
|
||||
_ws_url += "?" + "&".join(_ws_q)
|
||||
buttons.append({
|
||||
"widgettype": "Button",
|
||||
"options": {"label": "🗂 工作空间", "css": "small", "id": "menu_btn_ws"},
|
||||
"binds": [{
|
||||
"wid": "self", "event": "click", "actiontype": "urlwidget",
|
||||
"target": "self", "options": {"url": _ws_url},
|
||||
}],
|
||||
})
|
||||
|
||||
for i, m in enumerate(menus):
|
||||
label = str(m.get("label", "") or "")
|
||||
url = str(m.get("url", "") or "")
|
||||
if not url:
|
||||
continue
|
||||
require_project = bool(m.get("require_project", False))
|
||||
width = str(m.get("width", "85%") or "85%")
|
||||
height = str(m.get("height", "80%") or "80%")
|
||||
open_url = (entire_url("/pipeline_core/api/agent_menu_open.dspy")
|
||||
+ "?url=" + url + "&title=" + label
|
||||
+ "&width=" + width + "&height=" + height
|
||||
+ ("&require_project=1" if require_project else ""))
|
||||
if session_id:
|
||||
open_url += "&session_id=" + session_id
|
||||
if pipeline_id:
|
||||
open_url += "&pipeline_id=" + pipeline_id
|
||||
buttons = []
|
||||
for i, a in enumerate(actions):
|
||||
buttons.append({
|
||||
"widgettype": "Button",
|
||||
"options": {"label": label, "css": "small", "id": "menu_btn_%d" % i},
|
||||
"options": {"label": a["label"], "css": "small", "id": "menu_btn_%d" % i},
|
||||
"binds": [{
|
||||
"wid": "self", "event": "click", "actiontype": "urlwidget",
|
||||
"target": "self", "options": {"url": open_url},
|
||||
"target": "self", "options": {"url": a["url"]},
|
||||
}],
|
||||
})
|
||||
|
||||
|
||||
@ -17,6 +17,10 @@ dbname = get_module_dbname('pipeline_core')
|
||||
# 默认(手机端 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 产线;客户只看已购未到期。
|
||||
@ -69,8 +73,17 @@ try:
|
||||
ids = [(getattr(r, 'id', ''), getattr(r, 'name', '')) for r in (prec or [])]
|
||||
|
||||
for pid, pname in ids:
|
||||
items.append({"id": pid, "pipeline_id": pid,
|
||||
"name": pname or pid, "session_id": "m_" + pid})
|
||||
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 = []
|
||||
|
||||
|
||||
@ -1,3 +1,28 @@
|
||||
{% set embed = params_kw.get('embed','') == '1' %}
|
||||
{% set pl_id = params_kw.get('pipeline_id','') or '' %}
|
||||
{% if embed %}
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"width": "100%", "height": "100%", "padding": "0"},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "urlwidget",
|
||||
"options": {"url": "/pipeline_core/api/agent_menus.dspy?pipeline_id={{pl_id}}&session_id=m_{{pl_id}}"}
|
||||
},
|
||||
{
|
||||
"widgettype": "AgentIO",
|
||||
"options": {
|
||||
"css": "filler",
|
||||
"margin": "0 8px 8px 8px",
|
||||
"url": "/pipeline_core/api/agent_chat.dspy?pipeline_id={{pl_id}}&session_id=m_{{pl_id}}",
|
||||
"model_dataurl": "/pipeline_core/api/agent_model_options.dspy?capabilities=chat&pipeline_id={{pl_id}}&session_id=m_{{pl_id}}",
|
||||
"model_cwidth": 14,
|
||||
"placeholder": "输入你的需求..."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
{% else %}
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"width": "100%", "height": "100%", "padding": "0", "css": "pl-gate-root"},
|
||||
@ -91,3 +116,4 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user