120 lines
5.8 KiB
Plaintext
120 lines
5.8 KiB
Plaintext
# llm_wallet_todo_popup.dspy — 钱包余额不足待办详情弹窗(2026-09-11 用户定夺)
|
||
# 平台待办 source='llm_wallet' 的「查看内容并处理」入口。
|
||
# 入参: id=llm_wallet_<account_id> 或 account_id=<账号id>
|
||
# 展示账号钱包状态 + 充值表单(金额/备注)→ POST llm_account_recharge.dspy;
|
||
# 充值到账余额回升 → 待办由状态派生自动消失(provider 不再返回)。
|
||
|
||
import json as _json
|
||
|
||
uid = await get_user()
|
||
if not uid:
|
||
return {"widgettype": "Message", "options": {"title": "未登录", "message": "请先登录后查看待办"}}
|
||
|
||
pk = params_kw or {}
|
||
acc_id = str(pk.get('account_id') or '').strip()
|
||
if not acc_id:
|
||
raw = str(pk.get('id') or '').strip()
|
||
if raw.startswith('llm_wallet_'):
|
||
acc_id = raw[len('llm_wallet_'):]
|
||
else:
|
||
acc_id = raw
|
||
if not acc_id:
|
||
return {"widgettype": "Message", "options": {"title": "打开失败", "message": "缺少账号 id"}}
|
||
|
||
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, a.org_id, "
|
||
"v.name AS vendor_name, COALESCE(NULLIF(a.org_id,''), v.org_id, '0') AS owner_org "
|
||
"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", {})
|
||
trecs = await sor.sqlExe(
|
||
"SELECT params_value FROM params WHERE params_name='llm_wallet_balance_threshold' LIMIT 1", {})
|
||
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')可看全部;否则只看本属主机构的账号
|
||
if user_org != '0' and owner_org not in ('', user_org):
|
||
return {"widgettype": "Message", "options": {"title": "无权访问", "message": "该账号属于其他机构"}}
|
||
|
||
balance = float(row['balance'] or 0)
|
||
threshold = 5.0
|
||
try:
|
||
if trecs and str(trecs[0]['params_value'] or '').strip():
|
||
threshold = float(str(trecs[0]['params_value']).strip())
|
||
except Exception:
|
||
pass
|
||
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 元 | **门禁阈值**:%.2f 元 | **累计充值**:%.4f 元'
|
||
% (balance, threshold, float(row['total_recharge'] or 0)),
|
||
'**账号状态**:' + str(row['status'] or ''), '']
|
||
if balance < threshold:
|
||
head_md += ['> ⚠️ 余额低于门禁阈值——该账号已从模型调用轮询集剔除,'
|
||
'调用其下模型将顺延到其他账号;全部账号不足时调用报可行动错误。',
|
||
'> 充值到账后待办自动消失、账号自动恢复轮询。', '']
|
||
else:
|
||
head_md += ['> ✅ 余额已恢复到阈值以上,账号在轮询集中正常可用,本待办即将自动关闭。', '']
|
||
|
||
recharge_url = entire_url('/pipeline-llm/api/llm_account_recharge.dspy')
|
||
|
||
|
||
def _read_input_js(wid):
|
||
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();")
|
||
|
||
|
||
_tail = ("var pw=bricks.getWidgetById('llm_wallet_todo_pw',bricks.app);"
|
||
"if(pw&&pw.destroy){pw.destroy();}"
|
||
"if(window.refreshTodo){window.refreshTodo();}"
|
||
"if(d&&d.success){var mo=new bricks.Message({title:'充值成功',message:d.message||'钱包已充值'});mo.open();}"
|
||
"else{var mf=new bricks.Message({title:'充值失败',message:(d&&(d.message||d.error))||'充值失败'});mf.open();}")
|
||
|
||
do_js = (_read_input_js('llm_wallet_amt')
|
||
+ "var amt=parseFloat(cv);"
|
||
+ "if(isNaN(amt)||amt<=0){new bricks.Message({title:'请填写金额',message:'充值金额必须是大于 0 的数字'}).open();return;}"
|
||
+ _read_input_js('llm_wallet_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=await r.json();" + _tail)
|
||
|
||
sub = [
|
||
{"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_wallet_amt",
|
||
"options": {"name": "llm_wallet_amt", "placeholder": "如 100.00", "width": "160px"}},
|
||
{"widgettype": "UiText", "id": "llm_wallet_note",
|
||
"options": {"name": "llm_wallet_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}]}]}]
|
||
|
||
return {
|
||
"widgettype": "PopupWindow",
|
||
"id": "llm_wallet_todo_pw",
|
||
"options": {"title": "钱包充值 — " + acc_name, "width": "52%", "height": "46%",
|
||
"auto_open": True, "resizable": True},
|
||
"subwidgets": [{
|
||
"widgettype": "VScrollPanel",
|
||
"options": {"css": "filler", "width": "100%", "height": "100%", "padding": "14px"},
|
||
"subwidgets": sub}]
|
||
}
|