fix: avatar list fixes — full-width table, absolute photo URLs, global token balance

- Table width set to 100%
- Photo URLs resolved to absolute paths using AVATAR_BACKEND_URL
- Token balance now reads from global token_account table
- Config: added AVATAR_BACKEND_URL setting
This commit is contained in:
stefanfeng
2026-08-07 13:53:02 +08:00
parent 57af1c7db1
commit 6026b1279e
3 changed files with 32 additions and 5 deletions
+3
View File
@@ -28,6 +28,9 @@ class Settings(BaseSettings):
# 数字分身 SQLite 数据库路径(直连数字分身应用的 SQLite) # 数字分身 SQLite 数据库路径(直连数字分身应用的 SQLite)
AVATAR_DB_PATH: str = os.getenv("AVATAR_DB_PATH", "") AVATAR_DB_PATH: str = os.getenv("AVATAR_DB_PATH", "")
# 数字分身后端服务地址(用于拼接头像等文件 URL)
AVATAR_BACKEND_URL: str = os.getenv("AVATAR_BACKEND_URL", "")
# 日志目录 # 日志目录
LOG_DIR: str = "/app/logs" LOG_DIR: str = "/app/logs"
+28 -4
View File
@@ -44,6 +44,28 @@ def is_available() -> bool:
return engine is not None return engine is not None
def _resolve_photo_url(photo_url: str) -> str:
"""将相对路径的头像 URL 补全为绝对路径"""
if not photo_url:
return ""
if photo_url.startswith(("http://", "https://")):
return photo_url
base = settings.AVATAR_BACKEND_URL
if base:
base = base.rstrip("/")
return f"{base}{photo_url}"
return photo_url
def _get_global_token_balance(db: Session) -> int:
"""获取全局 token_account 余额(单行表)"""
try:
result = db.execute(text("SELECT balance FROM token_account LIMIT 1")).fetchone()
return result.balance if result and result.balance else 0
except Exception:
return 0
class AvatarService: class AvatarService:
@staticmethod @staticmethod
@@ -97,6 +119,7 @@ class AvatarService:
rows = db.execute(query, params).fetchall() rows = db.execute(query, params).fetchall()
items = [] items = []
global_token = _get_global_token_balance(db)
for row in rows: for row in rows:
config = {} config = {}
if row.config: if row.config:
@@ -113,10 +136,10 @@ class AvatarService:
"name": row.name, "name": row.name,
"display_name": row.display_name, "display_name": row.display_name,
"description": row.description or "", "description": row.description or "",
"photo_url": row.photo_url or "", "photo_url": _resolve_photo_url(row.photo_url),
"emoji": row.emoji or "🤖", "emoji": row.emoji or "🤖",
"status": row.status or "active", "status": row.status or "active",
"token_balance": row.token_balance or 0, "token_balance": global_token or (row.token_balance or 0),
"config": config, "config": config,
"owner_nickname": row.owner_nickname or "", "owner_nickname": row.owner_nickname or "",
"owner_phone": row.owner_phone or "", "owner_phone": row.owner_phone or "",
@@ -155,15 +178,16 @@ class AvatarService:
elif isinstance(row.config, dict): elif isinstance(row.config, dict):
config = row.config config = row.config
global_token = _get_global_token_balance(db)
return { return {
"id": row.id, "id": row.id,
"name": row.name, "name": row.name,
"display_name": row.display_name, "display_name": row.display_name,
"description": row.description or "", "description": row.description or "",
"photo_url": row.photo_url or "", "photo_url": _resolve_photo_url(row.photo_url),
"emoji": row.emoji or "🤖", "emoji": row.emoji or "🤖",
"status": row.status or "active", "status": row.status or "active",
"token_balance": row.token_balance or 0, "token_balance": global_token or (row.token_balance or 0),
"config": config, "config": config,
"owner_nickname": row.owner_nickname or "", "owner_nickname": row.owner_nickname or "",
"owner_phone": row.owner_phone or "", "owner_phone": row.owner_phone or "",
+1 -1
View File
@@ -259,7 +259,7 @@ onUnmounted(() => window.removeEventListener('page-refresh', loadAvatars))
<style scoped> <style scoped>
.filter-bar { display: flex; gap: 10px; margin-bottom: 12px; flex-wrap: wrap; } .filter-bar { display: flex; gap: 10px; margin-bottom: 12px; flex-wrap: wrap; }
.data-table { border-radius: 8px; overflow: hidden; } .data-table { border-radius: 8px; overflow: hidden; width: 100%; }
/* Detail panel */ /* Detail panel */
.detail-header { display: flex; align-items: center; } .detail-header { display: flex; align-items: center; }