feat(wallet): 供应商账号列表「充值登记」工具栏——选中账号行→弹窗输金额→balance+=充值(复用recharge_account:流水+total_recharge+治理缓存刷新),充值后列表自动刷新,机构隔离同待办弹窗
This commit is contained in:
parent
cc2e9c5a50
commit
a23a0193ab
@ -43,6 +43,32 @@
|
||||
},
|
||||
"confidential_fields": [
|
||||
"api_key"
|
||||
],
|
||||
"toolbar": {
|
||||
"tools": [
|
||||
{
|
||||
"name": "recharge",
|
||||
"label": "💰 充值登记",
|
||||
"selected_row": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "recharge",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "PopupWindow",
|
||||
"popup_options": {
|
||||
"title": "充值登记",
|
||||
"width": "46%",
|
||||
"height": "52%",
|
||||
"resizable": true
|
||||
},
|
||||
"options": {
|
||||
"url": "{{entire_url('../api/llm_account_recharge_popup.dspy')}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
99
wwwroot/api/llm_account_recharge_popup.dspy
Normal file
99
wwwroot/api/llm_account_recharge_popup.dspy
Normal file
@ -0,0 +1,99 @@
|
||||
# llm_account_recharge_popup.dspy — 供应商账号列表「充值登记」弹窗内容
|
||||
# 入口: json/llm_account_by_vendor.json 工具栏 recharge 按钮(selected_row) → binds
|
||||
# urlwidget → PopupWindow(外壳由 popup_options 生成,此处只返回内容 widget,
|
||||
# 返回 PopupWindow 会套娃——同 llm_call_trace_io.dspy 约定)。
|
||||
# 入参: 列表页 toolbar selected_row 自动注入整行数据(id=账号主键)。
|
||||
# 提交: POST llm_account_recharge.dspy → gateway.recharge_account:
|
||||
# balance += 充值金额、total_recharge 累加、写充值流水;余额回升后
|
||||
# 「钱包充值」待办由状态派生自动消失。
|
||||
|
||||
uid = await get_user()
|
||||
if not uid:
|
||||
return {"widgettype": "Message", "options": {"title": "提示", "message": "请先登录", "timeout": 3}}
|
||||
|
||||
acc_id = str((params_kw or {}).get('id') or '').strip()
|
||||
if not acc_id:
|
||||
return {"widgettype": "Message", "options": {"title": "打开失败", "message": "请先在列表中选中一个账号行"}}
|
||||
|
||||
user_org = str(await get_userorgid() or '0')
|
||||
dbname = get_module_dbname('pipeline-llm')
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
recs = await sor.sqlExe(
|
||||
"SELECT a.id, a.name, a.balance, a.total_recharge, a.status, "
|
||||
"COALESCE(NULLIF(a.org_id,''), v.org_id, '0') AS owner_org, v.name AS vendor_name "
|
||||
"FROM llm_account a LEFT JOIN llm_vendor v ON v.id=a.vendor_id "
|
||||
"WHERE a.id=${i}$ LIMIT 1", {"i": acc_id})
|
||||
await sor.sqlExe("COMMIT", {})
|
||||
|
||||
if not recs:
|
||||
return {"widgettype": "Message", "options": {"title": "打开失败", "message": "账号不存在或已删除"}}
|
||||
row = recs[0]
|
||||
owner_org = str(row['owner_org'] or '0')
|
||||
# 机构隔离:平台业主('0')可看全部;否则只看本属主机构的账号(同 llm_wallet_todo_popup)
|
||||
if user_org != '0' and owner_org not in ('', user_org):
|
||||
return {"widgettype": "Message", "options": {"title": "无权访问", "message": "该账号属于其他机构"}}
|
||||
|
||||
balance = float(row['balance'] or 0)
|
||||
acc_name = str(row['name'] or acc_id)
|
||||
vendor_name = str(row['vendor_name'] or '')
|
||||
|
||||
head_md = ['## 充值登记', '',
|
||||
'**账号**:' + (('【%s】' % vendor_name) if vendor_name else '') + acc_name,
|
||||
'**当前余额**:%.4f 元 | **累计充值**:%.4f 元 | **状态**:%s'
|
||||
% (balance, float(row['total_recharge'] or 0), str(row['status'] or '')),
|
||||
'',
|
||||
'> 确认后账号余额 = 当前余额 + 充值金额,并写入充值流水;'
|
||||
'余额回升到门禁阈值以上后该账号自动恢复模型调用轮询。']
|
||||
|
||||
recharge_url = entire_url('/pipeline-llm/api/llm_account_recharge.dspy')
|
||||
|
||||
|
||||
def _read_input_js(wid):
|
||||
# 弹窗内控件 getWidgetById 起点必须 bricks.app(DOM 挂 body 下,app.root 查不到)
|
||||
return ("var cw=bricks.getWidgetById(" + json.dumps(wid) + ",bricks.app);var cv='';"
|
||||
"if(cw){cv=(typeof cw.resultValue==='function')?cw.resultValue():"
|
||||
"((cw.dom_element&&cw.dom_element.value)||'');}"
|
||||
"cv=(cv===null||cv===undefined)?'':String(cv).trim();")
|
||||
|
||||
|
||||
# 成功:关弹窗(从内容控件沿 parent 链找 PopupWindow 外壳) + 刷新账号列表 + 提示;
|
||||
# 失败:弹窗保持打开,允许改金额重试。
|
||||
_close_and_refresh_js = (
|
||||
"var box=bricks.getWidgetById('llm_acc_recharge_box',bricks.app);"
|
||||
"var pw=box;while(pw&&!(pw instanceof bricks.PopupWindow)&&!(pw instanceof bricks.Popup)){pw=pw.parent;}"
|
||||
"if(pw){if(pw.destroy){pw.destroy();}else if(pw.dismiss){pw.dismiss();}}"
|
||||
"var t=bricks.getWidgetById('llm_account_tbl',bricks.app);"
|
||||
"if(t&&t.render){t.old_params=null;t.render({});}")
|
||||
|
||||
do_js = (_read_input_js('llm_acc_amt')
|
||||
+ "var amt=parseFloat(cv);"
|
||||
+ "if(isNaN(amt)||amt<=0){new bricks.Message({title:'请填写金额',message:'充值金额必须是大于 0 的数字'}).open();return;}"
|
||||
+ _read_input_js('llm_acc_note')
|
||||
+ "var r=await fetch(" + json.dumps(recharge_url) + ",{method:'POST',"
|
||||
"headers:{'Content-Type':'application/json'},"
|
||||
"body:JSON.stringify({account_id:" + json.dumps(acc_id) + ",amount:amt,note:cv})});"
|
||||
"var d=null;try{d=await r.json();}catch(e){}"
|
||||
+ "if(d&&d.success){" + _close_and_refresh_js
|
||||
+ "new bricks.Message({title:'充值成功',message:d.message||'账号余额已更新'}).open();}"
|
||||
+ "else{new bricks.Message({title:'充值失败',message:(d&&(d.message||d.error))||('请求失败 HTTP '+r.status)}).open();}")
|
||||
|
||||
return {
|
||||
"widgettype": "VBox",
|
||||
"id": "llm_acc_recharge_box",
|
||||
"options": {"width": "100%", "height": "100%", "padding": "16px", "gap": "12px"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "MdWidget", "options": {"mdtext": '\n'.join(head_md), "width": "100%"}},
|
||||
{"widgettype": "HBox",
|
||||
"options": {"width": "100%", "gap": "8px", "alignItems": "center"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "充值金额(元):", "cfontsize": 0.9, "color": "#334155"}},
|
||||
{"widgettype": "UiText", "id": "llm_acc_amt",
|
||||
"options": {"name": "llm_acc_amt", "placeholder": "如 100.00", "width": "160px"}},
|
||||
{"widgettype": "UiText", "id": "llm_acc_note",
|
||||
"options": {"name": "llm_acc_note", "placeholder": "备注(可选,如银行流水号)",
|
||||
"flex": "1 1 auto"}},
|
||||
{"widgettype": "Button",
|
||||
"options": {"label": "💰 确认充值", "css": "primary small"},
|
||||
"binds": [{"wid": "self", "event": "click", "actiontype": "script",
|
||||
"target": "self", "script": do_js}]}]}]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user