feat(llm): 供应商账号改为供应商CRUD子表(llm_account_by_vendor)——弹窗进入只显示/处理选定供应商账号;账号归属服务端守卫(vendor_id不可改/跨供应商禁删);删独立账号列表页(index.ui卡片同步移除)
This commit is contained in:
parent
c16bdb4a28
commit
34ef256fe6
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,6 +8,7 @@ dist/
|
||||
# CRUD generated directories (auto-generated by xls2ui at build time, NOT in repo)
|
||||
wwwroot/llm_vendor/
|
||||
wwwroot/llm_account/
|
||||
wwwroot/llm_account_by_vendor/
|
||||
wwwroot/llm_model/
|
||||
wwwroot/llm_api_profile/
|
||||
wwwroot/llm_org_policy/
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"tblname": "llm_account",
|
||||
"alias": "llm_account_by_vendor",
|
||||
"title": "供应商账号",
|
||||
"params": {
|
||||
"sortby": "name",
|
||||
@ -7,15 +8,10 @@
|
||||
"browserfields": {
|
||||
"exclouded": [
|
||||
"id",
|
||||
"api_key"
|
||||
"api_key",
|
||||
"vendor_id"
|
||||
],
|
||||
"alters": {
|
||||
"vendor_id": {
|
||||
"uitype": "code",
|
||||
"dataurl": "{{entire_url('../api/get_llm_vendor_options.dspy')}}",
|
||||
"valueField": "value",
|
||||
"textField": "text"
|
||||
},
|
||||
"status": {
|
||||
"uitype": "code",
|
||||
"dataurl": "{{entire_url('../api/get_llm_status_options.dspy')}}",
|
||||
@ -34,6 +30,7 @@
|
||||
"editexclouded": [
|
||||
"id",
|
||||
"org_id",
|
||||
"vendor_id",
|
||||
"balance",
|
||||
"total_recharge",
|
||||
"created_at",
|
||||
@ -30,6 +30,14 @@
|
||||
"new_data_url": "{{entire_url('../api/add_llm_vendor.dspy')}}",
|
||||
"update_data_url": "{{entire_url('../api/update_llm_vendor.dspy')}}",
|
||||
"delete_data_url": "{{entire_url('../api/delete_llm_vendor.dspy')}}"
|
||||
}
|
||||
},
|
||||
"subtables": [
|
||||
{
|
||||
"field": "vendor_id",
|
||||
"title": "供应商账号",
|
||||
"subtable": "llm_account_by_vendor",
|
||||
"url": "{{entire_url('/pipeline-llm/llm_account_by_vendor')}}"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,10 +222,18 @@ async def create_llm_account(params_kw):
|
||||
|
||||
|
||||
async def update_llm_account(params_kw):
|
||||
"""账号更新:api_key 非空才重新加密(空=不改)。"""
|
||||
"""账号更新:api_key 非空才重新加密(空=不改)。
|
||||
|
||||
vendor_id 归属不可改:账号在哪个供应商下创建就固定在哪个供应商下,
|
||||
防止子表(按供应商过滤)入口下篡改表单把账号挪到别的供应商。
|
||||
"""
|
||||
result = {'success': False, 'message': ''}
|
||||
try:
|
||||
data = _clean(params_kw)
|
||||
aid = data.get('id', '')
|
||||
if not aid:
|
||||
raise ValueError('缺少 id')
|
||||
data.pop('vendor_id', None)
|
||||
if data.get('api_key') and data['api_key'] != MASK:
|
||||
data['api_key'] = encrypt_api_key(data['api_key'])
|
||||
else:
|
||||
@ -243,17 +251,28 @@ async def update_llm_account(params_kw):
|
||||
|
||||
|
||||
async def delete_llm_account(params_kw):
|
||||
"""账号删除:被模型引用时禁止;带 vendor_id 时校验归属(子表范围隔离)。"""
|
||||
result = {'success': False, 'message': ''}
|
||||
try:
|
||||
aid = (params_kw or {}).get('id', '')
|
||||
pk = params_kw or {}
|
||||
aid = pk.get('id', '')
|
||||
if not aid:
|
||||
raise ValueError('缺少 id')
|
||||
db, dbname = _get_sor()
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
recs = await sor.sqlExe(
|
||||
"SELECT vendor_id FROM llm_account WHERE id=${a}$", {"a": aid})
|
||||
await sor.sqlExe("COMMIT", {})
|
||||
if not recs:
|
||||
raise ValueError('账号不存在')
|
||||
# 子表入口会带 vendor_id:校验账号确实属于该供应商,防跨供应商误删/越权删
|
||||
expect_vid = pk.get('vendor_id', '')
|
||||
if expect_vid and getattr(recs[0], 'vendor_id', '') != expect_vid:
|
||||
raise ValueError('账号不属于该供应商,禁止删除')
|
||||
cnt_recs = await sor.sqlExe(
|
||||
"SELECT COUNT(*) AS c FROM llm_model WHERE account_id=${a}$", {"a": aid})
|
||||
await sor.sqlExe("COMMIT", {})
|
||||
cnt = int(getattr(recs[0], 'c', 0)) if recs else 0
|
||||
cnt = int(getattr(cnt_recs[0], 'c', 0)) if cnt_recs else 0
|
||||
if cnt > 0:
|
||||
raise ValueError('该账号被 %d 个模型设为默认账号,请先解除后再删除' % cnt)
|
||||
await sor.sqlExe("DELETE FROM llm_account WHERE id=${a}$", {"a": aid})
|
||||
|
||||
@ -82,31 +82,6 @@
|
||||
{"widgettype": "Text", "options": {"text": "供应商协议 + 全球端点目录(国内/国际,配置一次全账号共用)", "cfontsize": 1.2}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"css": "card",
|
||||
"cwidth": 25,
|
||||
"padding": "16px",
|
||||
"cursor": "pointer"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.llm_content",
|
||||
"options": {
|
||||
"url": "{{entire_url('/pipeline-llm/llm_account')}}"
|
||||
},
|
||||
"mode": "replace"
|
||||
}
|
||||
],
|
||||
"subwidgets": [
|
||||
{"widgettype": "Title4", "options": {"text": "供应商账号(钱包)", "marginBottom": "8px"}},
|
||||
{"widgettype": "Text", "options": {"text": "多账号独立充值记账、选用端点;轮转突破供应商限流", "cfontsize": 1.2}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user