refactor(reallife_asset): uapi网关架构重构 + UI全面修复
架构变更: - 废弃volcengine_client.py直连,改为通过Sage uapi网关调用供应商API - rl_vendor_config表新增upappid和api_mapping(JSON)字段 - 新增_call_vendor()统一路由: vendor→upappid→apiname→UpAppApi.call() - 支持多供应商灵活映射,各家API数量/逻辑不同通过api_mapping配置 管理端UI: - vendor_config_manage.ui: Tabular列表展示供应商配置 - vendor_config_edit.ui: 供应商配置编辑页(AK/SK通过upapp/upappkey管理) - org_group_manage.ui: 机构映射管理页 - 新增api/get_upapp_list.dspy获取上位系统下拉选项 - 新增api/get_status_list.dspy获取状态下拉选项 客户端UI: - create_validate.ui: 真人认证页面,支持选择供应商创建H5认证 - upload_asset.ui: 上传素材页面,支持URL/base64上传 - index.ui: 新增客户端入口卡片(真人认证、上传素材) - 所有Form字段使用正确uitype(code/str/text),确保可输入 清理: - 废弃rl_app_user表,统一使用rl_asset_group+rl_org_group - 简化API签名,去除冗余apikey/secretkey透传
This commit is contained in:
parent
1d05b7e36b
commit
a21eabbb11
@ -11,7 +11,8 @@
|
||||
"vendor_group_id": {"title": "供应商组合ID", "widgettype": "Text"},
|
||||
"local_group_id": {"title": "本地组合ID", "widgettype": "Text"},
|
||||
"status": {"title": "状态", "widgettype": "Text"},
|
||||
"create_time": {"title": "创建时间", "widgettype": "Text"}
|
||||
"create_time": {"title": "创建时间", "widgettype": "Text"},
|
||||
"update_time": {"title": "更新时间", "widgettype": "Text"}
|
||||
},
|
||||
"editable": {
|
||||
"new_data_url": "{{entire_url('../api/rl_org_group_create.dspy')}}",
|
||||
|
||||
@ -3,10 +3,14 @@
|
||||
"alias": "rl_vendor_config_list",
|
||||
"title": "供应商配置管理",
|
||||
"params": {
|
||||
"sortby": ["create_time desc"],
|
||||
"logined_userorgid": "org_id",
|
||||
"browserfields": {
|
||||
"id": {"title": "ID", "widgettype": "Text"},
|
||||
"vendor": {"title": "供应商", "widgettype": "Text"},
|
||||
"vendor": {"title": "供应商标识", "widgettype": "Text"},
|
||||
"vendor_title": {"title": "供应商名称", "widgettype": "Text"},
|
||||
"upappid": {"title": "上位系统ID", "widgettype": "Text"},
|
||||
"api_mapping": {"title": "API映射", "widgettype": "Text"},
|
||||
"status": {"title": "状态", "widgettype": "Text"},
|
||||
"callback_url": {"title": "回调URL", "widgettype": "Text"},
|
||||
"create_time": {"title": "创建时间", "widgettype": "Text"},
|
||||
|
||||
@ -51,6 +51,11 @@
|
||||
"name": "create_time",
|
||||
"title": "创建时间",
|
||||
"type": "datetime"
|
||||
},
|
||||
{
|
||||
"name": "update_time",
|
||||
"title": "更新时间",
|
||||
"type": "datetime"
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
|
||||
@ -16,20 +16,29 @@
|
||||
},
|
||||
{
|
||||
"name": "vendor",
|
||||
"title": "供应商",
|
||||
"title": "供应商标识",
|
||||
"type": "str",
|
||||
"length": 50,
|
||||
"nullable": "no"
|
||||
},
|
||||
{
|
||||
"name": "ak",
|
||||
"title": "AccessKey(加密)",
|
||||
"type": "text"
|
||||
"name": "vendor_title",
|
||||
"title": "供应商名称",
|
||||
"type": "str",
|
||||
"length": 100
|
||||
},
|
||||
{
|
||||
"name": "sk",
|
||||
"title": "SecretKey(加密)",
|
||||
"type": "text"
|
||||
"name": "upappid",
|
||||
"title": "上位系统ID(uapi)",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no"
|
||||
},
|
||||
{
|
||||
"name": "api_mapping",
|
||||
"title": "API映射(JSON)",
|
||||
"type": "text",
|
||||
"nullable": "no"
|
||||
},
|
||||
{
|
||||
"name": "status",
|
||||
@ -62,13 +71,5 @@
|
||||
"idxfields": ["vendor"]
|
||||
}
|
||||
],
|
||||
"codes": [
|
||||
{
|
||||
"field": "vendor",
|
||||
"table": "appcodes_kv",
|
||||
"valuefield": "k",
|
||||
"textfield": "v",
|
||||
"cond": "parentid='rl_vendor'"
|
||||
}
|
||||
]
|
||||
"codes": []
|
||||
}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
"""
|
||||
reallife_asset module - Real Person Portrait Asset Management.
|
||||
Supports multiple vendors (Volcengine Ark, etc.) for managing
|
||||
real person portrait asset groups and assets.
|
||||
Supports multiple vendors via Sage uapi gateway.
|
||||
Vendor API routing: rl_vendor_config.api_mapping JSON maps internal
|
||||
operations to uapi apinames. Each vendor has its own upappid.
|
||||
"""
|
||||
import json
|
||||
from datetime import datetime
|
||||
@ -12,8 +13,7 @@ from ahserver.serverenv import ServerEnv
|
||||
from appPublic.log import debug, exception, error
|
||||
from appPublic.uniqueID import getID
|
||||
from appPublic.dictObject import DictObject
|
||||
|
||||
from .volcengine_client import get_vendor_client
|
||||
from uapi.uapi import UpAppApi
|
||||
|
||||
MODULE_NAME = "reallife_asset"
|
||||
|
||||
@ -23,28 +23,88 @@ def _get_dbname():
|
||||
return f(MODULE_NAME)
|
||||
|
||||
|
||||
def _get_client(vendor, apikey, secretkey):
|
||||
"""Get vendor API client."""
|
||||
return get_vendor_client(vendor, apikey, secretkey)
|
||||
async def _get_vendor_config(vendor):
|
||||
"""Look up vendor config: upappid + api_mapping from rl_vendor_config."""
|
||||
dbname = _get_dbname()
|
||||
db = DBPools()
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
recs = await sor.R("rl_vendor_config", {"vendor": vendor})
|
||||
if not recs:
|
||||
return {"success": False, "message": f"供应商配置不存在: {vendor}"}
|
||||
rec = recs[0]
|
||||
if rec.status != "active":
|
||||
return {"success": False, "message": f"供应商服务已停用: {vendor}"}
|
||||
try:
|
||||
api_mapping = json.loads(rec.api_mapping) if rec.api_mapping else {}
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
api_mapping = {}
|
||||
return {
|
||||
"success": True,
|
||||
"upappid": rec.upappid,
|
||||
"api_mapping": api_mapping,
|
||||
"callback_url": getattr(rec, "callback_url", ""),
|
||||
}
|
||||
|
||||
|
||||
def _get_apiname(api_mapping, operation):
|
||||
"""Get uapi apiname for an internal operation."""
|
||||
apiname = api_mapping.get(operation)
|
||||
if not apiname:
|
||||
return None
|
||||
return apiname
|
||||
|
||||
|
||||
async def _call_vendor(vendor, operation, params={}):
|
||||
"""
|
||||
Call vendor API via uapi gateway.
|
||||
Looks up upappid + apiname from rl_vendor_config, then calls UpAppApi.
|
||||
Returns parsed dict from response.
|
||||
"""
|
||||
cfg = await _get_vendor_config(vendor)
|
||||
if not cfg.get("success"):
|
||||
return cfg
|
||||
|
||||
upappid = cfg["upappid"]
|
||||
apiname = _get_apiname(cfg["api_mapping"], operation)
|
||||
if not apiname:
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"供应商 {vendor} 未配置操作 {operation}",
|
||||
}
|
||||
|
||||
# callerid = vendor name, used to look up API key in upappkey table
|
||||
callerid = vendor
|
||||
try:
|
||||
uapi = UpAppApi()
|
||||
raw = await uapi.call(upappid, apiname, callerid, params=params)
|
||||
if isinstance(raw, bytes):
|
||||
raw = raw.decode("utf-8")
|
||||
result = json.loads(raw) if raw else {}
|
||||
return result
|
||||
except Exception as e:
|
||||
error(f"_call_vendor {vendor}/{operation} error: {e}\\n{format_exc()}")
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Asset Group operations
|
||||
# Asset Group operations (admin-side, uses vendor config)
|
||||
# ============================================================
|
||||
|
||||
async def rl_create_validate_session(org_id, vendor, callback_url,
|
||||
project_name="default",
|
||||
apikey=None, secretkey=None,
|
||||
user_id=None):
|
||||
"""Create H5 verification session for real person auth."""
|
||||
client = _get_client(vendor, apikey, secretkey)
|
||||
result = client.create_visual_validate_session(callback_url, project_name)
|
||||
params = {
|
||||
"CallbackURL": callback_url or "",
|
||||
"ProjectName": project_name,
|
||||
}
|
||||
result = await _call_vendor(vendor, "create_session", params)
|
||||
|
||||
if "error" in result:
|
||||
return {"success": False, "message": result.get("error", "API调用失败")}
|
||||
if "error" in result or "Error" in result:
|
||||
return {"success": False, "message": result.get("error", result.get("Message", "API调用失败"))}
|
||||
|
||||
byted_token = result.get("BytedToken", "")
|
||||
h5_link = result.get("H5Link", "")
|
||||
byted_token = result.get("BytedToken", result.get("Result", {}).get("BytedToken", ""))
|
||||
h5_link = result.get("H5Link", result.get("Result", {}).get("H5Link", ""))
|
||||
|
||||
# Save to local DB
|
||||
dbname = _get_dbname()
|
||||
@ -63,7 +123,7 @@ async def rl_create_validate_session(org_id, vendor, callback_url,
|
||||
"status": "pending",
|
||||
"byted_token": byted_token,
|
||||
"h5_link": h5_link,
|
||||
"callback_url": callback_url,
|
||||
"callback_url": callback_url or "",
|
||||
"created_by": user_id or "",
|
||||
"create_time": now,
|
||||
"update_time": now,
|
||||
@ -76,8 +136,7 @@ async def rl_create_validate_session(org_id, vendor, callback_url,
|
||||
}
|
||||
|
||||
|
||||
async def rl_check_validate_result(local_group_id, vendor,
|
||||
apikey=None, secretkey=None):
|
||||
async def rl_check_validate_result(local_group_id, vendor, project_name="default"):
|
||||
"""Check real person validation result and get vendor Group ID."""
|
||||
dbname = _get_dbname()
|
||||
db = DBPools()
|
||||
@ -87,15 +146,18 @@ async def rl_check_validate_result(local_group_id, vendor,
|
||||
return {"success": False, "message": "本地记录不存在"}
|
||||
rec = recs[0]
|
||||
byted_token = rec.byted_token
|
||||
project_name = rec.project_name or "default"
|
||||
|
||||
client = _get_client(vendor, apikey, secretkey)
|
||||
result = client.get_visual_validate_result(byted_token, project_name)
|
||||
params = {
|
||||
"BytedToken": byted_token,
|
||||
"ProjectName": project_name,
|
||||
}
|
||||
result = await _call_vendor(vendor, "check_session", params)
|
||||
|
||||
if "error" in result:
|
||||
return {"success": False, "message": result.get("error", "查询失败")}
|
||||
if "error" in result or "Error" in result:
|
||||
return {"success": False, "message": result.get("error", result.get("Message", "查询失败"))}
|
||||
|
||||
vendor_group_id = result.get("GroupId", "")
|
||||
r = result.get("Result", result)
|
||||
vendor_group_id = r.get("GroupId", result.get("GroupId", ""))
|
||||
if not vendor_group_id:
|
||||
return {"success": False, "message": "尚未完成认证或认证失败"}
|
||||
|
||||
@ -113,35 +175,36 @@ async def rl_check_validate_result(local_group_id, vendor,
|
||||
return {"success": True, "vendor_group_id": vendor_group_id}
|
||||
|
||||
|
||||
async def rl_create_asset(org_id, local_group_id, source_url,
|
||||
async def rl_create_asset(org_id, vendor_group_id, source_url,
|
||||
asset_type="Image", name="",
|
||||
vendor=None, apikey=None, secretkey=None,
|
||||
vendor=None, project_name="default",
|
||||
user_id=None):
|
||||
"""Upload asset to vendor and create local record."""
|
||||
dbname = _get_dbname()
|
||||
db = DBPools()
|
||||
|
||||
# Find the group to get vendor and local_group_id
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
recs = await sor.R("rl_asset_group", {"id": local_group_id})
|
||||
recs = await sor.R("rl_asset_group", {"vendor_group_id": vendor_group_id})
|
||||
if not recs:
|
||||
return {"success": False, "message": "素材组合不存在"}
|
||||
grp = recs[0]
|
||||
vendor = vendor or grp.vendor
|
||||
vendor_group_id = grp.vendor_group_id
|
||||
project_name = grp.project_name or "default"
|
||||
local_group_id = grp.id
|
||||
project_name = grp.project_name or project_name
|
||||
|
||||
if not vendor_group_id:
|
||||
return {"success": False, "message": "素材组合尚未完成真人认证"}
|
||||
# Call vendor API
|
||||
params = {
|
||||
"GroupId": vendor_group_id,
|
||||
"URL": source_url,
|
||||
"AssetType": asset_type,
|
||||
"ProjectName": project_name,
|
||||
}
|
||||
if name:
|
||||
params["Name"] = name
|
||||
result = await _call_vendor(vendor, "upload_asset", params)
|
||||
|
||||
client = _get_client(vendor, apikey, secretkey)
|
||||
result = client.create_asset(
|
||||
vendor_group_id, source_url, asset_type, name, project_name
|
||||
)
|
||||
|
||||
vendor_asset_id = result.get("Id", "")
|
||||
if not vendor_asset_id and "error" not in result:
|
||||
# Try nested result structure
|
||||
r = result.get("Result", {})
|
||||
vendor_asset_id = r.get("Id", "")
|
||||
vendor_asset_id = result.get("Id", result.get("Result", {}).get("Id", ""))
|
||||
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
asset_id = getID()
|
||||
@ -166,17 +229,17 @@ async def rl_create_asset(org_id, local_group_id, source_url,
|
||||
"update_time": now,
|
||||
})
|
||||
|
||||
has_error = "error" in result or "Error" in result
|
||||
return {
|
||||
"success": "error" not in result,
|
||||
"success": not has_error,
|
||||
"id": asset_id,
|
||||
"vendor_asset_id": vendor_asset_id,
|
||||
"status": "Processing",
|
||||
"message": result.get("error", ""),
|
||||
"message": result.get("error", result.get("Message", "")),
|
||||
}
|
||||
|
||||
|
||||
async def rl_sync_asset_status(asset_id, vendor=None,
|
||||
apikey=None, secretkey=None):
|
||||
async def rl_sync_asset_status(asset_id):
|
||||
"""Sync asset status from vendor."""
|
||||
dbname = _get_dbname()
|
||||
db = DBPools()
|
||||
@ -185,25 +248,25 @@ async def rl_sync_asset_status(asset_id, vendor=None,
|
||||
if not recs:
|
||||
return {"success": False, "message": "素材不存在"}
|
||||
rec = recs[0]
|
||||
vendor = vendor or rec.vendor
|
||||
vendor = rec.vendor
|
||||
vendor_asset_id = rec.vendor_asset_id
|
||||
project_name = rec.project_name or "default"
|
||||
|
||||
if not vendor_asset_id:
|
||||
return {"success": False, "message": "无供应商端资产ID"}
|
||||
|
||||
client = _get_client(vendor, apikey, secretkey)
|
||||
result = client.get_asset(vendor_asset_id, project_name)
|
||||
params = {
|
||||
"Id": vendor_asset_id,
|
||||
"ProjectName": project_name,
|
||||
}
|
||||
result = await _call_vendor(vendor, "get_asset", params)
|
||||
|
||||
if "error" in result:
|
||||
return {"success": False, "message": result.get("error", "查询失败")}
|
||||
if "error" in result or "Error" in result:
|
||||
return {"success": False, "message": result.get("error", result.get("Message", "查询失败"))}
|
||||
|
||||
# Extract status from result (may be nested under Result)
|
||||
status = result.get("Status", "")
|
||||
if not status:
|
||||
r = result.get("Result", {})
|
||||
status = r.get("Status", result.get("status", ""))
|
||||
url = result.get("URL", result.get("Result", {}).get("URL", ""))
|
||||
r = result.get("Result", result)
|
||||
status = r.get("Status", result.get("Status", ""))
|
||||
url = r.get("URL", result.get("URL", ""))
|
||||
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
@ -219,8 +282,7 @@ async def rl_sync_asset_status(asset_id, vendor=None,
|
||||
return {"success": True, "status": status, "url": url}
|
||||
|
||||
|
||||
async def rl_delete_asset(asset_id, vendor=None,
|
||||
apikey=None, secretkey=None):
|
||||
async def rl_delete_asset(asset_id):
|
||||
"""Delete asset from vendor and local DB."""
|
||||
dbname = _get_dbname()
|
||||
db = DBPools()
|
||||
@ -229,15 +291,14 @@ async def rl_delete_asset(asset_id, vendor=None,
|
||||
if not recs:
|
||||
return {"success": False, "message": "素材不存在"}
|
||||
rec = recs[0]
|
||||
vendor = vendor or rec.vendor
|
||||
vendor = rec.vendor
|
||||
vendor_asset_id = rec.vendor_asset_id
|
||||
project_name = rec.project_name or "default"
|
||||
|
||||
# Delete from vendor
|
||||
if vendor_asset_id:
|
||||
client = _get_client(vendor, apikey, secretkey)
|
||||
result = client.delete_asset(vendor_asset_id, project_name)
|
||||
debug(f"vendor delete asset: {result}")
|
||||
params = {"Id": vendor_asset_id, "ProjectName": project_name}
|
||||
await _call_vendor(vendor, "delete_asset", params)
|
||||
|
||||
# Delete local
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
@ -246,8 +307,7 @@ async def rl_delete_asset(asset_id, vendor=None,
|
||||
return {"success": True}
|
||||
|
||||
|
||||
async def rl_delete_group(local_group_id, vendor=None,
|
||||
apikey=None, secretkey=None):
|
||||
async def rl_delete_group(local_group_id):
|
||||
"""Delete asset group from vendor and local DB (cascade)."""
|
||||
dbname = _get_dbname()
|
||||
db = DBPools()
|
||||
@ -256,15 +316,14 @@ async def rl_delete_group(local_group_id, vendor=None,
|
||||
if not recs:
|
||||
return {"success": False, "message": "素材组合不存在"}
|
||||
rec = recs[0]
|
||||
vendor = vendor or rec.vendor
|
||||
vendor = rec.vendor
|
||||
vendor_group_id = rec.vendor_group_id
|
||||
project_name = rec.project_name or "default"
|
||||
|
||||
# Delete from vendor
|
||||
if vendor_group_id:
|
||||
client = _get_client(vendor, apikey, secretkey)
|
||||
result = client.delete_asset_group(vendor_group_id, project_name)
|
||||
debug(f"vendor delete group: {result}")
|
||||
params = {"Id": vendor_group_id, "ProjectName": project_name}
|
||||
await _call_vendor(vendor, "delete_group", params)
|
||||
|
||||
# Delete local (cascade)
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
@ -274,12 +333,14 @@ async def rl_delete_group(local_group_id, vendor=None,
|
||||
return {"success": True}
|
||||
|
||||
|
||||
async def rl_sync_group_from_vendor(org_id, vendor,
|
||||
apikey=None, secretkey=None,
|
||||
project_name="default"):
|
||||
async def rl_sync_group_from_vendor(org_id, vendor, project_name="default"):
|
||||
"""Sync asset groups from vendor to local DB."""
|
||||
client = _get_client(vendor, apikey, secretkey)
|
||||
result = client.list_asset_groups(project_name=project_name)
|
||||
params = {
|
||||
"Filter": {"GroupType": "LivenessFace"},
|
||||
"PageNumber": 1,
|
||||
"PageSize": 100,
|
||||
}
|
||||
result = await _call_vendor(vendor, "list_groups", params)
|
||||
|
||||
items = result.get("Items", result.get("Result", {}).get("Items", []))
|
||||
synced = 0
|
||||
@ -291,7 +352,6 @@ async def rl_sync_group_from_vendor(org_id, vendor,
|
||||
vgid = item.get("Id", "")
|
||||
if not vgid:
|
||||
continue
|
||||
# Check if exists
|
||||
existing = await sor.R("rl_asset_group", {
|
||||
"vendor": vendor,
|
||||
"vendor_group_id": vgid,
|
||||
@ -325,8 +385,7 @@ async def rl_sync_group_from_vendor(org_id, vendor,
|
||||
return {"success": True, "synced": synced}
|
||||
|
||||
|
||||
async def rl_sync_assets_from_vendor(org_id, local_group_id,
|
||||
vendor=None, apikey=None, secretkey=None):
|
||||
async def rl_sync_assets_from_vendor(org_id, local_group_id):
|
||||
"""Sync assets for a group from vendor to local DB."""
|
||||
dbname = _get_dbname()
|
||||
db = DBPools()
|
||||
@ -335,15 +394,19 @@ async def rl_sync_assets_from_vendor(org_id, local_group_id,
|
||||
if not recs:
|
||||
return {"success": False, "message": "素材组合不存在"}
|
||||
grp = recs[0]
|
||||
vendor = vendor or grp.vendor
|
||||
vendor = grp.vendor
|
||||
vendor_group_id = grp.vendor_group_id
|
||||
project_name = grp.project_name or "default"
|
||||
|
||||
if not vendor_group_id:
|
||||
return {"success": False, "message": "无供应商端组合ID"}
|
||||
|
||||
client = _get_client(vendor, apikey, secretkey)
|
||||
result = client.list_assets(group_ids=[vendor_group_id])
|
||||
params = {
|
||||
"Filter": {"GroupType": "LivenessFace", "GroupIds": [vendor_group_id]},
|
||||
"PageNumber": 1,
|
||||
"PageSize": 100,
|
||||
}
|
||||
result = await _call_vendor(vendor, "list_assets", params)
|
||||
|
||||
items = result.get("Items", result.get("Result", {}).get("Items", []))
|
||||
synced = 0
|
||||
@ -388,47 +451,28 @@ async def rl_sync_assets_from_vendor(org_id, local_group_id,
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Downapp User API Proxies
|
||||
# Downapp User API Proxies (client-facing via dapi Bearer auth)
|
||||
# ============================================================
|
||||
|
||||
async def _get_vendor_keys(vendor="volcengine"):
|
||||
"""Helper: Get vendor AK/SK from config table."""
|
||||
dbname = _get_dbname()
|
||||
db = DBPools()
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
recs = await sor.R("rl_vendor_config", {"vendor": vendor})
|
||||
if not recs:
|
||||
return {"success": False, "message": "供应商配置不存在"}
|
||||
rec = recs[0]
|
||||
if rec.status != "active":
|
||||
return {"success": False, "message": f"供应商服务已停用"}
|
||||
async def rl_verify_user(org_id, user_id, vendor, project_name="default"):
|
||||
"""User proxy: Create H5 verification session via uapi gateway."""
|
||||
callback_cfg = await _get_vendor_config(vendor)
|
||||
if not callback_cfg.get("success"):
|
||||
return callback_cfg
|
||||
callback_url = callback_cfg.get("callback_url", "")
|
||||
|
||||
env = ServerEnv()
|
||||
ak = env.password_decode(rec.ak)
|
||||
sk = env.password_decode(rec.sk)
|
||||
return {"success": True, "ak": ak, "sk": sk, "callback_url": rec.callback_url}
|
||||
params = {
|
||||
"CallbackURL": callback_url,
|
||||
"ProjectName": project_name,
|
||||
}
|
||||
result = await _call_vendor(vendor, "create_session", params)
|
||||
|
||||
if "error" in result or "Error" in result:
|
||||
return {"success": False, "message": result.get("error", result.get("Message", "API调用失败"))}
|
||||
|
||||
async def rl_verify_user(org_id, user_id, project_name="default"):
|
||||
"""User proxy: Verify vendor config -> Call vendor -> Save org-group mapping."""
|
||||
keys = await _get_vendor_keys()
|
||||
if not keys.get("success"):
|
||||
return keys
|
||||
byted_token = result.get("BytedToken", result.get("Result", {}).get("BytedToken", ""))
|
||||
h5_link = result.get("H5Link", result.get("Result", {}).get("H5Link", ""))
|
||||
|
||||
# Call Vendor API
|
||||
client = _get_client("volcengine", keys["ak"], keys["sk"])
|
||||
callback_url = keys.get("callback_url", "")
|
||||
|
||||
result = client.create_visual_validate_session(callback_url, project_name)
|
||||
|
||||
if "error" in result:
|
||||
return {"success": False, "message": result.get("error", "API调用失败")}
|
||||
|
||||
byted_token = result.get("BytedToken", "")
|
||||
h5_link = result.get("H5Link", "")
|
||||
|
||||
# Save local record for checking status later
|
||||
# We use rl_asset_group for temporary state tracking
|
||||
gid = getID()
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
db = DBPools()
|
||||
@ -436,7 +480,7 @@ async def rl_verify_user(org_id, user_id, project_name="default"):
|
||||
await sor.I("rl_asset_group", {
|
||||
"id": gid,
|
||||
"org_id": org_id,
|
||||
"vendor": "volcengine",
|
||||
"vendor": vendor,
|
||||
"name": f"待认证-{user_id}",
|
||||
"title": f"待认证",
|
||||
"group_type": "LivenessFace",
|
||||
@ -458,73 +502,12 @@ async def rl_verify_user(org_id, user_id, project_name="default"):
|
||||
}
|
||||
|
||||
|
||||
async def rl_check_validate_and_map(local_group_id, project_name="default"):
|
||||
"""Internal: Check validation result and update rl_org_group mapping."""
|
||||
keys = await _get_vendor_keys()
|
||||
if not keys.get("success"):
|
||||
return keys
|
||||
|
||||
dbname = _get_dbname()
|
||||
db = DBPools()
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
recs = await sor.R("rl_asset_group", {"id": local_group_id})
|
||||
if not recs:
|
||||
return {"success": False, "message": "本地记录不存在"}
|
||||
rec = recs[0]
|
||||
byted_token = rec.byted_token
|
||||
org_id = rec.org_id
|
||||
|
||||
# Call Vendor
|
||||
client = _get_client("volcengine", keys["ak"], keys["sk"])
|
||||
result = client.get_visual_validate_result(byted_token, project_name)
|
||||
|
||||
if "error" in result:
|
||||
return {"success": False, "message": result.get("error", "查询失败")}
|
||||
|
||||
vendor_group_id = result.get("GroupId", "")
|
||||
if not vendor_group_id:
|
||||
return {"success": False, "message": "尚未完成认证或认证失败"}
|
||||
|
||||
# Update mapping table rl_org_group
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
mapping_id = getID()
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
# Check if mapping exists
|
||||
existing = await sor.R("rl_org_group", {"org_id": org_id, "vendor": "volcengine"})
|
||||
if existing:
|
||||
await sor.U("rl_org_group", {
|
||||
"vendor_group_id": vendor_group_id,
|
||||
"local_group_id": local_group_id,
|
||||
"update_time": now # add update_time field if needed, or just update
|
||||
}, {"id": existing[0].id})
|
||||
else:
|
||||
await sor.I("rl_org_group", {
|
||||
"id": mapping_id,
|
||||
"org_id": org_id,
|
||||
"vendor": "volcengine",
|
||||
"vendor_group_id": vendor_group_id,
|
||||
"local_group_id": local_group_id,
|
||||
"status": "active",
|
||||
"create_time": now
|
||||
})
|
||||
|
||||
# Update rl_asset_group status
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
await sor.U("rl_asset_group", {
|
||||
"vendor_group_id": vendor_group_id,
|
||||
"status": "active",
|
||||
"update_time": now,
|
||||
}, {"id": local_group_id})
|
||||
|
||||
return {"success": True, "vendor_group_id": vendor_group_id}
|
||||
|
||||
|
||||
async def rl_upload_user(org_id, vendor_group_id, source_url, asset_type, name, user_id):
|
||||
"""User proxy: Validate Org-Group mapping -> Get Keys -> Upload."""
|
||||
# 1. Validate: vendor_group_id belongs to this org
|
||||
"""User proxy: Validate Org-Group mapping -> Upload via uapi."""
|
||||
dbname = _get_dbname()
|
||||
db = DBPools()
|
||||
|
||||
# 1. Validate: vendor_group_id belongs to this org
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
recs = await sor.R("rl_org_group", {
|
||||
"org_id": org_id,
|
||||
@ -532,27 +515,22 @@ async def rl_upload_user(org_id, vendor_group_id, source_url, asset_type, name,
|
||||
})
|
||||
if not recs:
|
||||
return {"success": False, "message": "无效的素材组合ID或无权访问"}
|
||||
|
||||
# Get local_group_id for asset record
|
||||
local_group_id = recs[0].local_group_id
|
||||
vendor = recs[0].vendor
|
||||
|
||||
# 2. Get Keys
|
||||
keys = await _get_vendor_keys()
|
||||
if not keys.get("success"):
|
||||
return keys
|
||||
# 2. Upload via uapi
|
||||
params = {
|
||||
"GroupId": vendor_group_id,
|
||||
"URL": source_url,
|
||||
"AssetType": asset_type,
|
||||
"ProjectName": "default",
|
||||
}
|
||||
if name:
|
||||
params["Name"] = name
|
||||
result = await _call_vendor(vendor, "upload_asset", params)
|
||||
|
||||
# 3. Upload
|
||||
client = _get_client("volcengine", keys["ak"], keys["sk"])
|
||||
result = client.create_asset(
|
||||
vendor_group_id, source_url, asset_type, name
|
||||
)
|
||||
vendor_asset_id = result.get("Id", result.get("Result", {}).get("Id", ""))
|
||||
|
||||
vendor_asset_id = result.get("Id", "")
|
||||
if not vendor_asset_id and "error" not in result:
|
||||
r = result.get("Result", {})
|
||||
vendor_asset_id = r.get("Id", "")
|
||||
|
||||
# 4. Save Asset Record
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
asset_id = getID()
|
||||
asset_uri = f"asset://{vendor_asset_id}" if vendor_asset_id else ""
|
||||
@ -562,7 +540,7 @@ async def rl_upload_user(org_id, vendor_group_id, source_url, asset_type, name,
|
||||
"id": asset_id,
|
||||
"org_id": org_id,
|
||||
"group_id": local_group_id,
|
||||
"vendor": "volcengine",
|
||||
"vendor": vendor,
|
||||
"vendor_asset_id": vendor_asset_id,
|
||||
"asset_type": asset_type,
|
||||
"name": name or source_url.split("/")[-1][:50],
|
||||
@ -576,50 +554,48 @@ async def rl_upload_user(org_id, vendor_group_id, source_url, asset_type, name,
|
||||
"update_time": now,
|
||||
})
|
||||
|
||||
has_error = "error" in result or "Error" in result
|
||||
return {
|
||||
"success": "error" not in result,
|
||||
"success": not has_error,
|
||||
"id": asset_id,
|
||||
"vendor_asset_id": vendor_asset_id,
|
||||
"status": "Processing",
|
||||
"message": result.get("error", ""),
|
||||
"message": result.get("error", result.get("Message", "")),
|
||||
}
|
||||
|
||||
|
||||
async def rl_sync_asset_status_user(org_id, asset_id, user_id):
|
||||
"""User proxy: Validate ownership -> Get Keys -> Sync Status."""
|
||||
"""User proxy: Validate ownership -> Sync Status via uapi."""
|
||||
dbname = _get_dbname()
|
||||
db = DBPools()
|
||||
|
||||
# Validate asset belongs to org
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
recs = await sor.R("rl_asset", {"id": asset_id, "org_id": org_id})
|
||||
if not recs:
|
||||
return {"success": False, "message": "素材不存在或无权访问"}
|
||||
rec = recs[0]
|
||||
vendor = rec.vendor
|
||||
vendor_asset_id = rec.vendor_asset_id
|
||||
project_name = rec.project_name or "default"
|
||||
|
||||
keys = await _get_vendor_keys()
|
||||
if not keys.get("success"):
|
||||
return keys
|
||||
params = {
|
||||
"Id": vendor_asset_id,
|
||||
"ProjectName": project_name,
|
||||
}
|
||||
result = await _call_vendor(vendor, "get_asset", params)
|
||||
|
||||
# Sync with vendor
|
||||
client = _get_client("volcengine", keys["ak"], keys["sk"])
|
||||
result = client.get_asset(vendor_asset_id)
|
||||
if "error" in result or "Error" in result:
|
||||
return {"success": False, "message": result.get("error", result.get("Message", "查询失败"))}
|
||||
|
||||
if "error" in result:
|
||||
return {"success": False, "message": result.get("error", "查询失败")}
|
||||
r = result.get("Result", result)
|
||||
status = r.get("Status", result.get("Status", ""))
|
||||
url = r.get("URL", result.get("URL", ""))
|
||||
|
||||
status = result.get("Status", "")
|
||||
if not status:
|
||||
r = result.get("Result", {})
|
||||
status = r.get("Status", result.get("status", ""))
|
||||
url = result.get("URL", result.get("Result", {}).get("URL", ""))
|
||||
|
||||
# Update local
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
upd = {"status": status, "update_time": now, "vendor_response": json.dumps(result, ensure_ascii=False)}
|
||||
if url: upd["url"] = url
|
||||
if url:
|
||||
upd["url"] = url
|
||||
await sor.U("rl_asset", upd, {"id": asset_id})
|
||||
|
||||
return {"success": True, "status": status, "url": url}
|
||||
@ -627,14 +603,14 @@ async def rl_sync_asset_status_user(org_id, asset_id, user_id):
|
||||
|
||||
async def rl_handle_callback(byted_token, project_name="default"):
|
||||
"""
|
||||
Callback handler: Volcengine POSTs here after H5 auth completes.
|
||||
Looks up local group by byted_token, queries vendor for result,
|
||||
then registers rl_org_group mapping.
|
||||
Callback handler: vendor POSTs here after H5 auth completes.
|
||||
Looks up local group by byted_token (which includes vendor field),
|
||||
queries vendor for result, then registers rl_org_group mapping.
|
||||
"""
|
||||
dbname = _get_dbname()
|
||||
db = DBPools()
|
||||
|
||||
# 1. Find local group by byted_token
|
||||
# 1. Find local group by byted_token — vendor comes from this record
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
recs = await sor.R("rl_asset_group", {"byted_token": byted_token})
|
||||
if not recs:
|
||||
@ -642,8 +618,8 @@ async def rl_handle_callback(byted_token, project_name="default"):
|
||||
rec = recs[0]
|
||||
local_group_id = rec.id
|
||||
org_id = rec.org_id
|
||||
vendor = rec.vendor
|
||||
|
||||
# Already processed?
|
||||
if rec.status == "active" and rec.vendor_group_id:
|
||||
debug(f"callback already processed for group {local_group_id}")
|
||||
return {
|
||||
@ -653,37 +629,29 @@ async def rl_handle_callback(byted_token, project_name="default"):
|
||||
"message": "已处理",
|
||||
}
|
||||
|
||||
# 2. Get vendor keys
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
vrecs = await sor.R("rl_vendor_config", {"vendor": "volcengine"})
|
||||
if not vrecs:
|
||||
return {"success": False, "message": "供应商配置不存在"}
|
||||
vrec = vrecs[0]
|
||||
if vrec.status != "active":
|
||||
return {"success": False, "message": "供应商服务已停用"}
|
||||
env = ServerEnv()
|
||||
ak = env.password_decode(vrec.ak)
|
||||
sk = env.password_decode(vrec.sk)
|
||||
# 2. Query vendor for result via uapi
|
||||
params = {
|
||||
"BytedToken": byted_token,
|
||||
"ProjectName": project_name,
|
||||
}
|
||||
result = await _call_vendor(vendor, "check_session", params)
|
||||
|
||||
# 3. Query vendor for result
|
||||
client = _get_client("volcengine", ak, sk)
|
||||
result = client.get_visual_validate_result(byted_token, project_name)
|
||||
|
||||
if "error" in result:
|
||||
if "error" in result or "Error" in result:
|
||||
error(f"callback query vendor error: {result}")
|
||||
return {"success": False, "message": result.get("error", "查询失败")}
|
||||
return {"success": False, "message": result.get("error", result.get("Message", "查询失败"))}
|
||||
|
||||
vendor_group_id = result.get("GroupId", "")
|
||||
r = result.get("Result", result)
|
||||
vendor_group_id = r.get("GroupId", result.get("GroupId", ""))
|
||||
if not vendor_group_id:
|
||||
return {"success": False, "message": "尚未完成认证或认证失败"}
|
||||
|
||||
# 4. Register rl_org_group mapping
|
||||
# 3. Register rl_org_group mapping
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
mapping_id = getID()
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
existing = await sor.R("rl_org_group", {
|
||||
"org_id": org_id,
|
||||
"vendor": "volcengine",
|
||||
"vendor": vendor,
|
||||
})
|
||||
if existing:
|
||||
await sor.U("rl_org_group", {
|
||||
@ -695,14 +663,14 @@ async def rl_handle_callback(byted_token, project_name="default"):
|
||||
await sor.I("rl_org_group", {
|
||||
"id": mapping_id,
|
||||
"org_id": org_id,
|
||||
"vendor": "volcengine",
|
||||
"vendor": vendor,
|
||||
"vendor_group_id": vendor_group_id,
|
||||
"local_group_id": local_group_id,
|
||||
"status": "active",
|
||||
"create_time": now,
|
||||
})
|
||||
|
||||
# 5. Update rl_asset_group status
|
||||
# 4. Update rl_asset_group status
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
await sor.U("rl_asset_group", {
|
||||
"vendor_group_id": vendor_group_id,
|
||||
@ -760,7 +728,6 @@ def load_reallife_asset():
|
||||
|
||||
# Downapp user APIs
|
||||
g.rl_verify_user = rl_verify_user
|
||||
g.rl_check_validate_and_map = rl_check_validate_and_map
|
||||
g.rl_upload_user = rl_upload_user
|
||||
g.rl_sync_asset_status_user = rl_sync_asset_status_user
|
||||
g.rl_handle_callback = rl_handle_callback
|
||||
|
||||
10
wwwroot/api/get_asset_type_list.dspy
Normal file
10
wwwroot/api/get_asset_type_list.dspy
Normal file
@ -0,0 +1,10 @@
|
||||
import json
|
||||
from appPublic.log import debug
|
||||
|
||||
rows = [
|
||||
{"value": "Image", "text": "图片"},
|
||||
{"value": "Video", "text": "视频"},
|
||||
{"value": "Audio", "text": "音频"}
|
||||
]
|
||||
debug(f"get_asset_type_list: {rows}")
|
||||
return json.dumps(rows, ensure_ascii=False)
|
||||
11
wwwroot/api/get_rl_org_group_list.dspy
Normal file
11
wwwroot/api/get_rl_org_group_list.dspy
Normal file
@ -0,0 +1,11 @@
|
||||
org_id = (await get_userorgid()) or '0'
|
||||
dbname = get_module_dbname('reallife_asset')
|
||||
db = DBPools()
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
ns = dict(params_kw)
|
||||
ns['org_id'] = org_id
|
||||
recs = await sor.R('rl_org_group', ns)
|
||||
total = len(recs)
|
||||
data = [dict(r) for r in recs]
|
||||
|
||||
return {"data": data, "total": total, "status": "ok"}
|
||||
11
wwwroot/api/get_rl_vendor_config_list.dspy
Normal file
11
wwwroot/api/get_rl_vendor_config_list.dspy
Normal file
@ -0,0 +1,11 @@
|
||||
org_id = (await get_userorgid()) or '0'
|
||||
dbname = get_module_dbname('reallife_asset')
|
||||
db = DBPools()
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
ns = dict(params_kw)
|
||||
ns['org_id'] = org_id
|
||||
recs = await sor.R('rl_vendor_config', ns)
|
||||
total = len(recs)
|
||||
data = [dict(r) for r in recs]
|
||||
|
||||
return {"data": data, "total": total, "status": "ok"}
|
||||
9
wwwroot/api/get_status_list.dspy
Normal file
9
wwwroot/api/get_status_list.dspy
Normal file
@ -0,0 +1,9 @@
|
||||
import json
|
||||
from appPublic.log import debug
|
||||
|
||||
rows = [
|
||||
{"value": "active", "text": "启用"},
|
||||
{"value": "inactive", "text": "停用"}
|
||||
]
|
||||
debug(f"get_status_list: {rows}")
|
||||
return json.dumps(rows, ensure_ascii=False)
|
||||
16
wwwroot/api/get_upapp_list.dspy
Normal file
16
wwwroot/api/get_upapp_list.dspy
Normal file
@ -0,0 +1,16 @@
|
||||
import json
|
||||
from sqlor.dbpools import DBPools
|
||||
from appPublic.log import debug
|
||||
|
||||
ns = params_kw.copy()
|
||||
dbname = get_module_dbname('uapi')
|
||||
db = DBPools()
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
recs = await sor.R("upapp", {"status": "1"})
|
||||
|
||||
rows = []
|
||||
for r in recs:
|
||||
rows.append({"value": r.id, "text": f"{r.name}({r.title})" if r.title else r.name})
|
||||
|
||||
debug(f"get_upapp_list: {rows}")
|
||||
return json.dumps(rows, ensure_ascii=False)
|
||||
14
wwwroot/api/get_vendor_list.dspy
Normal file
14
wwwroot/api/get_vendor_list.dspy
Normal file
@ -0,0 +1,14 @@
|
||||
import json
|
||||
from sqlor.dbpools import DBPools
|
||||
from appPublic.log import debug
|
||||
|
||||
ns = params_kw.copy()
|
||||
dbname = get_module_dbname('reallife_asset')
|
||||
db = DBPools()
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
recs = await sor.R("rl_vendor_config", {"status": "active"})
|
||||
rows = []
|
||||
for r in recs:
|
||||
rows.append({"value": r.vendor, "text": r.vendor})
|
||||
debug(f"get_vendor_list: {rows}")
|
||||
return json.dumps(rows, ensure_ascii=False)
|
||||
@ -1,22 +1,26 @@
|
||||
org_id = (await get_userorgid()) or '0'
|
||||
user_id = await get_user()
|
||||
group_id = params_kw.get('group_id', '')
|
||||
vendor_group_id = params_kw.get('vendor_group_id', '')
|
||||
source_url = params_kw.get('source_url', '')
|
||||
asset_type = params_kw.get('asset_type', 'Image')
|
||||
name = params_kw.get('name', '')
|
||||
apikey = params_kw.get('apikey', '')
|
||||
secretkey = params_kw.get('secretkey', '')
|
||||
|
||||
if not group_id:
|
||||
return {"success": False, "message": "请选择素材组合"}
|
||||
if not vendor_group_id:
|
||||
return {"success": False, "message": "请提供供应商组合ID"}
|
||||
if not source_url:
|
||||
return {"success": False, "message": "请提供素材URL"}
|
||||
if not apikey or not secretkey:
|
||||
return {"success": False, "message": "请提供供应商 API Key"}
|
||||
|
||||
result = await rl_create_asset(
|
||||
org_id, group_id, source_url,
|
||||
org_id, vendor_group_id, source_url,
|
||||
asset_type=asset_type, name=name,
|
||||
apikey=apikey, secretkey=secretkey, user_id=user_id
|
||||
user_id=user_id
|
||||
)
|
||||
return result
|
||||
|
||||
import json
|
||||
return json.dumps({
|
||||
"widgettype": "Message",
|
||||
"options": {
|
||||
"message": f"素材上传已提交: {result.get('vendor_asset_id', '')}" if result.get('success') else result.get('message', '上传失败'),
|
||||
"type": "success" if result.get('success') else "error"
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
org_id = (await get_userorgid()) or '0'
|
||||
rid = params_kw.get('id', '')
|
||||
apikey = params_kw.get('apikey', '')
|
||||
secretkey = params_kw.get('secretkey', '')
|
||||
|
||||
if apikey and secretkey:
|
||||
result = await rl_delete_asset(rid, apikey=apikey, secretkey=secretkey)
|
||||
return result
|
||||
if not rid:
|
||||
return {"success": False, "message": "id required"}
|
||||
|
||||
# Local-only delete
|
||||
dbname = get_module_dbname('reallife_asset')
|
||||
db = DBPools()
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
await sor.D("rl_asset", {"id": rid, "org_id": org_id})
|
||||
result = await rl_delete_asset(rid)
|
||||
|
||||
return {"success": True, "message": "本地删除成功"}
|
||||
import json
|
||||
return json.dumps({
|
||||
"widgettype": "Message",
|
||||
"options": {
|
||||
"message": "删除成功" if result.get("success") else result.get("message", "删除失败"),
|
||||
"type": "success" if result.get("success") else "error"
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,18 +1,24 @@
|
||||
org_id = (await get_userorgid()) or '0'
|
||||
user_id = await get_user()
|
||||
vendor = params_kw.get('vendor', 'volcengine')
|
||||
vendor = params_kw.get('vendor', '')
|
||||
callback_url = params_kw.get('callback_url', '')
|
||||
project_name = params_kw.get('project_name', 'default')
|
||||
apikey = params_kw.get('apikey', '')
|
||||
secretkey = params_kw.get('secretkey', '')
|
||||
|
||||
if not vendor:
|
||||
return {"success": False, "message": "请选择供应商"}
|
||||
if not callback_url:
|
||||
return {"success": False, "message": "callback_url 不能为空"}
|
||||
if not apikey or not secretkey:
|
||||
return {"success": False, "message": "请提供供应商 API Key (apikey/secretkey)"}
|
||||
|
||||
result = await rl_create_validate_session(
|
||||
org_id, vendor, callback_url, project_name,
|
||||
apikey=apikey, secretkey=secretkey, user_id=user_id
|
||||
user_id=user_id
|
||||
)
|
||||
return result
|
||||
|
||||
import json
|
||||
return json.dumps({
|
||||
"widgettype": "Message",
|
||||
"options": {
|
||||
"message": f"认证链接已生成: {result.get('h5_link', '')}",
|
||||
"type": "success" if result.get('success') else "error"
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,17 +1,16 @@
|
||||
org_id = (await get_userorgid()) or '0'
|
||||
rid = params_kw.get('id', '')
|
||||
apikey = params_kw.get('apikey', '')
|
||||
secretkey = params_kw.get('secretkey', '')
|
||||
|
||||
if apikey and secretkey:
|
||||
result = await rl_delete_group(rid, apikey=apikey, secretkey=secretkey)
|
||||
return result
|
||||
if not rid:
|
||||
return {"success": False, "message": "id required"}
|
||||
|
||||
# Local-only delete
|
||||
dbname = get_module_dbname('reallife_asset')
|
||||
db = DBPools()
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
await sor.D("rl_asset", {"group_id": rid})
|
||||
await sor.D("rl_asset_group", {"id": rid, "org_id": org_id})
|
||||
result = await rl_delete_group(rid)
|
||||
|
||||
return {"success": True, "message": "本地删除成功"}
|
||||
import json
|
||||
return json.dumps({
|
||||
"widgettype": "Message",
|
||||
"options": {
|
||||
"message": "删除成功" if result.get("success") else result.get("message", "删除失败"),
|
||||
"type": "success" if result.get("success") else "error"
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,18 +1,15 @@
|
||||
import json
|
||||
|
||||
# Volcengine callback POSTs JSON body with BytedToken and result info.
|
||||
# Vendor callback POSTs JSON body with BytedToken.
|
||||
# The callback URL is configured when calling CreateVisualValidateSession.
|
||||
# Typical payload: {"BytedToken": "...", "ReqUUID": "...", "Status": "..."}
|
||||
|
||||
# Try to parse JSON body first
|
||||
body_str = http_request.get("body", "") or ""
|
||||
byted_token = ""
|
||||
project_name = "default"
|
||||
|
||||
try:
|
||||
body = json.loads(body_str) if body_str else {}
|
||||
byted_token = body.get("BytedToken", "")
|
||||
# Also check alternative field names
|
||||
if not byted_token:
|
||||
byted_token = body.get("byted_token", "")
|
||||
if not byted_token:
|
||||
@ -20,12 +17,12 @@ try:
|
||||
except:
|
||||
byted_token = ""
|
||||
|
||||
# Fallback: check query params
|
||||
if not byted_token:
|
||||
byted_token = params_kw.get("BytedToken", params_kw.get("byted_token", ""))
|
||||
|
||||
if not byted_token:
|
||||
return {"success": False, "message": "缺少 BytedToken 参数"}
|
||||
|
||||
result = await rl_handle_callback(byted_token, project_name)
|
||||
# vendor is determined by looking up the session record
|
||||
result = await rl_handle_callback(byted_token, project_name="default")
|
||||
return result
|
||||
|
||||
@ -2,19 +2,30 @@ org_id = params_kw.get('org_id', (await get_userorgid()) or '0')
|
||||
id = params_kw.get('id', getID())
|
||||
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# Encrypt keys
|
||||
ak = params_kw.get('ak', '')
|
||||
sk = params_kw.get('sk', '')
|
||||
env = ServerEnv()
|
||||
if ak: ak = env.password_encode(ak)
|
||||
if sk: sk = env.password_encode(sk)
|
||||
vendor = params_kw.get('vendor', '')
|
||||
upappid = params_kw.get('upappid', '')
|
||||
api_mapping = params_kw.get('api_mapping', '{}')
|
||||
|
||||
if not vendor:
|
||||
return {"success": False, "message": "供应商标识不能为空"}
|
||||
if not upappid:
|
||||
return {"success": False, "message": "上位系统ID不能为空"}
|
||||
|
||||
# Validate api_mapping is valid JSON
|
||||
import json
|
||||
try:
|
||||
api_mapping_dict = json.loads(api_mapping) if api_mapping else {}
|
||||
api_mapping = json.dumps(api_mapping_dict, ensure_ascii=False)
|
||||
except json.JSONDecodeError:
|
||||
return {"success": False, "message": "API映射必须是有效的JSON"}
|
||||
|
||||
data = {
|
||||
"id": id,
|
||||
"org_id": org_id,
|
||||
"vendor": params_kw.get('vendor', 'volcengine'),
|
||||
"ak": ak,
|
||||
"sk": sk,
|
||||
"vendor": vendor,
|
||||
"vendor_title": params_kw.get('vendor_title', ''),
|
||||
"upappid": upappid,
|
||||
"api_mapping": api_mapping,
|
||||
"status": params_kw.get('status', 'active'),
|
||||
"callback_url": params_kw.get('callback_url', ''),
|
||||
"create_time": now,
|
||||
|
||||
@ -8,19 +8,19 @@ async with db.sqlorContext(dbname) as sor:
|
||||
if not recs: return {"success": False, "message": "Not found"}
|
||||
|
||||
upd = {}
|
||||
for k in ['status', 'callback_url', 'vendor']:
|
||||
if params_kw.get(k):
|
||||
for k in ['status', 'callback_url', 'vendor', 'vendor_title', 'upappid']:
|
||||
if params_kw.get(k) is not None:
|
||||
upd[k] = params_kw.get(k)
|
||||
|
||||
# Encrypt keys
|
||||
ak = params_kw.get('ak', None)
|
||||
sk = params_kw.get('sk', None)
|
||||
if ak is not None:
|
||||
env = ServerEnv()
|
||||
upd['ak'] = env.password_encode(ak)
|
||||
if sk is not None:
|
||||
env = ServerEnv()
|
||||
upd['sk'] = env.password_encode(sk)
|
||||
# Update api_mapping if provided
|
||||
api_mapping = params_kw.get('api_mapping', None)
|
||||
if api_mapping is not None:
|
||||
import json
|
||||
try:
|
||||
api_mapping_dict = json.loads(api_mapping) if api_mapping else {}
|
||||
upd['api_mapping'] = json.dumps(api_mapping_dict, ensure_ascii=False)
|
||||
except json.JSONDecodeError:
|
||||
return {"success": False, "message": "API映射必须是有效的JSON"}
|
||||
|
||||
upd['update_time'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
|
||||
@ -1,4 +1,13 @@
|
||||
vendor = params_kw.get('vendor', '')
|
||||
project_name = params_kw.get('project_name', 'default')
|
||||
|
||||
result = await rl_verify_user((await get_userorgid()) or '0', (await get_user()) or '', project_name)
|
||||
if not vendor:
|
||||
return {"success": False, "message": "请指定供应商"}
|
||||
|
||||
result = await rl_verify_user(
|
||||
(await get_userorgid()) or '0',
|
||||
(await get_user()) or '',
|
||||
vendor,
|
||||
project_name
|
||||
)
|
||||
return result
|
||||
|
||||
@ -1,11 +1,15 @@
|
||||
asset_id = params_kw.get('asset_id', '')
|
||||
apikey = params_kw.get('apikey', '')
|
||||
secretkey = params_kw.get('secretkey', '')
|
||||
|
||||
if not asset_id:
|
||||
return {"success": False, "message": "asset_id 不能为空"}
|
||||
if not apikey or not secretkey:
|
||||
return {"success": False, "message": "请提供供应商 API Key"}
|
||||
|
||||
result = await rl_sync_asset_status(asset_id, apikey=apikey, secretkey=secretkey)
|
||||
return result
|
||||
result = await rl_sync_asset_status(asset_id)
|
||||
|
||||
import json
|
||||
return json.dumps({
|
||||
"widgettype": "Message",
|
||||
"options": {
|
||||
"message": f"状态同步完成: {result.get('status', '')}" if result.get('success') else result.get('message', '同步失败'),
|
||||
"type": "success" if result.get('success') else "error"
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
org_id = (await get_userorgid()) or '0'
|
||||
group_id = params_kw.get('group_id', '')
|
||||
apikey = params_kw.get('apikey', '')
|
||||
secretkey = params_kw.get('secretkey', '')
|
||||
|
||||
if not group_id:
|
||||
return {"success": False, "message": "group_id 不能为空"}
|
||||
if not apikey or not secretkey:
|
||||
return {"success": False, "message": "请提供供应商 API Key"}
|
||||
return {"success": False, "message": "请选择素材组合"}
|
||||
|
||||
result = await rl_sync_assets_from_vendor(
|
||||
org_id, group_id, apikey=apikey, secretkey=secretkey
|
||||
)
|
||||
return result
|
||||
result = await rl_sync_assets_from_vendor(org_id, group_id)
|
||||
|
||||
import json
|
||||
return json.dumps({
|
||||
"widgettype": "Message",
|
||||
"options": {
|
||||
"message": f"素材同步完成,共 {result.get('synced', 0)} 条记录",
|
||||
"type": "success" if result.get('success') else "error"
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,14 +1,17 @@
|
||||
org_id = (await get_userorgid()) or '0'
|
||||
vendor = params_kw.get('vendor', 'volcengine')
|
||||
apikey = params_kw.get('apikey', '')
|
||||
secretkey = params_kw.get('secretkey', '')
|
||||
vendor = params_kw.get('vendor', '')
|
||||
project_name = params_kw.get('project_name', 'default')
|
||||
|
||||
if not apikey or not secretkey:
|
||||
return {"success": False, "message": "请提供供应商 API Key"}
|
||||
if not vendor:
|
||||
return {"success": False, "message": "请选择供应商"}
|
||||
|
||||
result = await rl_sync_group_from_vendor(
|
||||
org_id, vendor, apikey=apikey, secretkey=secretkey,
|
||||
project_name=project_name
|
||||
)
|
||||
return result
|
||||
result = await rl_sync_group_from_vendor(org_id, vendor, project_name)
|
||||
|
||||
import json
|
||||
return json.dumps({
|
||||
"widgettype": "Message",
|
||||
"options": {
|
||||
"message": f"同步完成,共 {result.get('synced', 0)} 条记录",
|
||||
"type": "success" if result.get('success') else "error"
|
||||
}
|
||||
})
|
||||
|
||||
@ -25,9 +25,7 @@
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "上传素材",
|
||||
"bgcolor": "#1890ff",
|
||||
"color": "#fff"
|
||||
"label": "上传素材"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
|
||||
@ -6,61 +6,130 @@
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"alignItems": "center",
|
||||
"marginBottom": "16px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Title4",
|
||||
"options": {
|
||||
"text": "创建真人认证",
|
||||
"fontSize": "20px",
|
||||
"fontWeight": "bold",
|
||||
"marginBottom": "16px"
|
||||
"fontWeight": "600"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Filler"
|
||||
},
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "返回首页"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.rl_content",
|
||||
"options": {
|
||||
"url": "{{entire_url('index.ui')}}"
|
||||
},
|
||||
"mode": "replace"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VScrollPanel",
|
||||
"options": {
|
||||
"height": "500px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"padding": "16px",
|
||||
"spacing": 12
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Form",
|
||||
"id": "validate_form",
|
||||
"options": {
|
||||
"url": "{{entire_url('api/rl_asset_group_create.dspy')}}",
|
||||
"method": "POST",
|
||||
"submit_url": "{{entire_url('api/rl_asset_group_create.dspy')}}",
|
||||
"fields": [
|
||||
{
|
||||
"uitype": "code",
|
||||
"name": "vendor",
|
||||
"label": "供应商",
|
||||
"type": "select",
|
||||
"options": [
|
||||
{
|
||||
"value": "volcengine",
|
||||
"text": "火山方舟"
|
||||
"dataurl": "{{entire_url('api/get_vendor_list.dspy')}}",
|
||||
"data_field": "value",
|
||||
"text_field": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"value": "kling",
|
||||
"text": "可灵"
|
||||
"uitype": "str",
|
||||
"name": "callback_url",
|
||||
"label": "回调URL",
|
||||
"placeholder": "https://your-domain.com/reallife_asset/api/rl_callback.dspy",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"uitype": "str",
|
||||
"name": "project_name",
|
||||
"label": "项目名",
|
||||
"placeholder": "default",
|
||||
"value": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"gap": "12px",
|
||||
"marginTop": "16px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "提交"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "script",
|
||||
"target": "self",
|
||||
"script": "var f=bricks.getWidgetById('validate_form',bricks.app);if(f)f.submit()"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "callback_url",
|
||||
"label": "回调URL",
|
||||
"type": "text",
|
||||
"placeholder": "https://your-domain.com/callback"
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "重置"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"name": "project_name",
|
||||
"label": "项目名",
|
||||
"type": "text",
|
||||
"default": "default"
|
||||
},
|
||||
{
|
||||
"name": "apikey",
|
||||
"label": "Access Key",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"name": "secretkey",
|
||||
"label": "Secret Key",
|
||||
"type": "password"
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "script",
|
||||
"target": "self",
|
||||
"script": "var f=bricks.getWidgetById('validate_form',bricks.app);if(f)f.reset()"
|
||||
}
|
||||
],
|
||||
"submit_label": "生成认证链接"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -25,9 +25,7 @@
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "创建真人认证",
|
||||
"bgcolor": "#1890ff",
|
||||
"color": "#fff"
|
||||
"label": "创建真人认证"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
@ -45,9 +43,7 @@
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "从供应商同步",
|
||||
"bgcolor": "#52c41a",
|
||||
"color": "#fff"
|
||||
"label": "从供应商同步"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
|
||||
172
wwwroot/index.ui
172
wwwroot/index.ui
@ -23,13 +23,93 @@
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"bgcolor": "#FFFFFF",
|
||||
"css": "card",
|
||||
"padding": "20px",
|
||||
"cursor": "pointer",
|
||||
"borderRadius": "8px",
|
||||
"boxShadow": "0 2px 8px rgba(0,0,0,0.1)"
|
||||
"border": "none"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.rl_content",
|
||||
"options": {
|
||||
"url": "{{entire_url('create_validate.ui')}}"
|
||||
},
|
||||
"mode": "replace"
|
||||
}
|
||||
],
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "🔐 真人认证",
|
||||
"fontSize": "18px",
|
||||
"fontWeight": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "创建真人认证会话,获取H5认证链接",
|
||||
"fontSize": "14px",
|
||||
"color": "#666"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"css": "card",
|
||||
"padding": "20px",
|
||||
"cursor": "pointer",
|
||||
"borderRadius": "8px",
|
||||
"border": "none"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.rl_content",
|
||||
"options": {
|
||||
"url": "{{entire_url('upload_asset.ui')}}"
|
||||
},
|
||||
"mode": "replace"
|
||||
}
|
||||
],
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "📤 上传素材",
|
||||
"fontSize": "18px",
|
||||
"fontWeight": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "上传素材到供应商(支持URL/base64)",
|
||||
"fontSize": "14px",
|
||||
"color": "#666"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"css": "card",
|
||||
"padding": "20px",
|
||||
"cursor": "pointer",
|
||||
"borderRadius": "8px",
|
||||
"border": "none"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
@ -63,13 +143,13 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"bgcolor": "#FFFFFF",
|
||||
"css": "card",
|
||||
"padding": "20px",
|
||||
"cursor": "pointer",
|
||||
"borderRadius": "8px",
|
||||
"boxShadow": "0 2px 8px rgba(0,0,0,0.1)"
|
||||
"border": "none"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
@ -101,6 +181,86 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"css": "card",
|
||||
"padding": "20px",
|
||||
"cursor": "pointer",
|
||||
"borderRadius": "8px",
|
||||
"border": "none"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.rl_content",
|
||||
"options": {
|
||||
"url": "{{entire_url('vendor_config_manage.ui')}}"
|
||||
},
|
||||
"mode": "replace"
|
||||
}
|
||||
],
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "⚙️ 供应商配置",
|
||||
"fontSize": "18px",
|
||||
"fontWeight": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "管理供应商AK/SK和回调URL",
|
||||
"fontSize": "14px",
|
||||
"color": "#666"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"css": "card",
|
||||
"padding": "20px",
|
||||
"cursor": "pointer",
|
||||
"borderRadius": "8px",
|
||||
"border": "none"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.rl_content",
|
||||
"options": {
|
||||
"url": "{{entire_url('org_group_manage.ui')}}"
|
||||
},
|
||||
"mode": "replace"
|
||||
}
|
||||
],
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "🔗 机构映射管理",
|
||||
"fontSize": "18px",
|
||||
"fontWeight": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "查看/管理机构和供应商组合的映射关系",
|
||||
"fontSize": "14px",
|
||||
"color": "#666"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
25
wwwroot/org_group_manage.ui
Normal file
25
wwwroot/org_group_manage.ui
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"padding": "16px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "机构映射管理",
|
||||
"fontSize": "20px",
|
||||
"fontWeight": "bold",
|
||||
"marginBottom": "16px"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "DataViewer",
|
||||
"options": {
|
||||
"data_url": "{{entire_url('api/get_rl_org_group_list.dspy')}}",
|
||||
"crud_url": "{{entire_url('rl_org_group_list')}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -14,43 +14,54 @@
|
||||
"marginBottom": "16px"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "VScrollPanel",
|
||||
"options": {
|
||||
"height": "300px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"padding": "8px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Form",
|
||||
"id": "sync_form",
|
||||
"options": {
|
||||
"url": "{{entire_url('api/sync_from_vendor.dspy')}}",
|
||||
"method": "POST",
|
||||
"submit_url": "{{entire_url('api/sync_from_vendor.dspy')}}",
|
||||
"fields": [
|
||||
{
|
||||
"uitype": "code",
|
||||
"name": "vendor",
|
||||
"label": "供应商",
|
||||
"type": "select",
|
||||
"options": [
|
||||
"dataurl": "{{entire_url('api/get_vendor_list.dspy')}}",
|
||||
"data_field": "value",
|
||||
"text_field": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"value": "volcengine",
|
||||
"text": "火山方舟"
|
||||
"uitype": "str",
|
||||
"name": "project_name",
|
||||
"label": "项目名",
|
||||
"placeholder": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"name": "project_name",
|
||||
"label": "项目名",
|
||||
"type": "text",
|
||||
"default": "default"
|
||||
},
|
||||
{
|
||||
"name": "apikey",
|
||||
"label": "Access Key",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"name": "secretkey",
|
||||
"label": "Secret Key",
|
||||
"type": "password"
|
||||
"wid": "self",
|
||||
"event": "submited",
|
||||
"actiontype": "script",
|
||||
"target": "self",
|
||||
"script": "await bricks.show_resp_message_or_error(event.params)"
|
||||
}
|
||||
],
|
||||
"submit_label": "开始同步"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -6,70 +6,136 @@
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"alignItems": "center",
|
||||
"marginBottom": "16px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Title4",
|
||||
"options": {
|
||||
"text": "上传素材",
|
||||
"fontSize": "20px",
|
||||
"fontWeight": "bold",
|
||||
"marginBottom": "16px"
|
||||
"fontWeight": "600"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Filler"
|
||||
},
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "返回首页"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.rl_content",
|
||||
"options": {
|
||||
"url": "{{entire_url('index.ui')}}"
|
||||
},
|
||||
"mode": "replace"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VScrollPanel",
|
||||
"options": {
|
||||
"height": "600px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"padding": "16px",
|
||||
"spacing": 12
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Form",
|
||||
"id": "upload_form",
|
||||
"options": {
|
||||
"url": "{{entire_url('api/rl_asset_create.dspy')}}",
|
||||
"method": "POST",
|
||||
"submit_url": "{{entire_url('api/rl_asset_create.dspy')}}",
|
||||
"fields": [
|
||||
{
|
||||
"name": "group_id",
|
||||
"label": "素材组合",
|
||||
"type": "text",
|
||||
"placeholder": "选择本地组合ID"
|
||||
"uitype": "str",
|
||||
"name": "vendor_group_id",
|
||||
"label": "供应商组合ID",
|
||||
"placeholder": "输入已通过认证的 vendor_group_id",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"uitype": "text",
|
||||
"name": "source_url",
|
||||
"label": "素材URL",
|
||||
"type": "text",
|
||||
"placeholder": "https://... 可公开访问的图片/视频URL"
|
||||
"label": "素材URL或base64",
|
||||
"rows": 4,
|
||||
"placeholder": "https://... 可公开访问的图片URL\n或\ndata:image/png;base64,...",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"uitype": "code",
|
||||
"name": "asset_type",
|
||||
"label": "素材类型",
|
||||
"type": "select",
|
||||
"options": [
|
||||
{
|
||||
"value": "Image",
|
||||
"text": "图片"
|
||||
"dataurl": "{{entire_url('api/get_asset_type_list.dspy')}}",
|
||||
"data_field": "value",
|
||||
"text_field": "text"
|
||||
},
|
||||
{
|
||||
"value": "Video",
|
||||
"text": "视频"
|
||||
"uitype": "str",
|
||||
"name": "name",
|
||||
"label": "素材名称",
|
||||
"placeholder": "可选,默认使用URL最后一部分"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": "Audio",
|
||||
"text": "音频"
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"gap": "12px",
|
||||
"marginTop": "16px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "提交"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "script",
|
||||
"target": "self",
|
||||
"script": "var f=bricks.getWidgetById('upload_form',bricks.app);if(f)f.submit()"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"label": "素材名称",
|
||||
"type": "text"
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "重置"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"name": "apikey",
|
||||
"label": "Access Key",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"name": "secretkey",
|
||||
"label": "Secret Key",
|
||||
"type": "password"
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "script",
|
||||
"target": "self",
|
||||
"script": "var f=bricks.getWidgetById('upload_form',bricks.app);if(f)f.reset()"
|
||||
}
|
||||
],
|
||||
"submit_label": "上传素材"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
155
wwwroot/vendor_config_edit.ui
Normal file
155
wwwroot/vendor_config_edit.ui
Normal file
@ -0,0 +1,155 @@
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"padding": "16px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"alignItems": "center",
|
||||
"marginBottom": "16px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Title4",
|
||||
"options": {
|
||||
"text": "供应商配置",
|
||||
"fontWeight": "600"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Filler"
|
||||
},
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "返回列表"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.rl_content",
|
||||
"options": {
|
||||
"url": "{{entire_url('vendor_config_manage.ui')}}"
|
||||
},
|
||||
"mode": "replace"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VScrollPanel",
|
||||
"options": {
|
||||
"height": "600px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"padding": "16px",
|
||||
"spacing": 12
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Form",
|
||||
"id": "vendor_config_form",
|
||||
"options": {
|
||||
"submit_url": "{{entire_url('api/rl_vendor_config_create.dspy')}}",
|
||||
"fields": [
|
||||
{
|
||||
"uitype": "str",
|
||||
"name": "vendor",
|
||||
"label": "供应商标识",
|
||||
"placeholder": "如 volcengine",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"uitype": "str",
|
||||
"name": "vendor_title",
|
||||
"label": "供应商名称",
|
||||
"placeholder": "如火山引擎"
|
||||
},
|
||||
{
|
||||
"uitype": "code",
|
||||
"name": "upappid",
|
||||
"label": "上位系统(uapi)",
|
||||
"dataurl": "{{entire_url('api/get_upapp_list.dspy')}}",
|
||||
"data_field": "value",
|
||||
"text_field": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"uitype": "text",
|
||||
"name": "api_mapping",
|
||||
"label": "API映射(JSON)",
|
||||
"rows": 8,
|
||||
"placeholder": '{\"create_session\":\"CreateVisualValidateSession\",\"get_result\":\"GetVisualValidateResult\",\"upload_asset\":\"CreateAsset\",\"get_asset\":\"GetAsset\",\"list_assets\":\"ListAssets\",\"list_groups\":\"ListAssetGroups\",\"delete_asset\":\"DeleteAsset\",\"delete_group\":\"DeleteAssetGroup\"}'
|
||||
},
|
||||
{
|
||||
"uitype": "code",
|
||||
"name": "status",
|
||||
"label": "状态",
|
||||
"dataurl": "{{entire_url('api/get_status_list.dspy')}}",
|
||||
"data_field": "value",
|
||||
"text_field": "text"
|
||||
},
|
||||
{
|
||||
"uitype": "str",
|
||||
"name": "callback_url",
|
||||
"label": "回调URL",
|
||||
"placeholder": "https://your-domain.com/reallife_asset/api/rl_callback.dspy"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {
|
||||
"gap": "12px",
|
||||
"marginTop": "16px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "提交"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "script",
|
||||
"target": "self",
|
||||
"script": "var f=bricks.getWidgetById('vendor_config_form',bricks.app);if(f)f.submit()"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "重置"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "script",
|
||||
"target": "self",
|
||||
"script": "var f=bricks.getWidgetById('vendor_config_form',bricks.app);if(f)f.reset()"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
25
wwwroot/vendor_config_manage.ui
Normal file
25
wwwroot/vendor_config_manage.ui
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"padding": "16px"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "供应商配置管理",
|
||||
"fontSize": "20px",
|
||||
"fontWeight": "bold",
|
||||
"marginBottom": "16px"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "DataViewer",
|
||||
"options": {
|
||||
"data_url": "{{entire_url('api/get_rl_vendor_config_list.dspy')}}",
|
||||
"crud_url": "{{entire_url('rl_vendor_config_list')}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user