fix: v0.19.3 admin settings GET 补返回 1080P 两个单价字段
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 11m45s

v0.19.0 做 1080P 时 QuotaConfig 加了 base_token_price_1080p 和
base_token_price_1080p_video 字段, serializer (PUT) 和计费逻辑
(_get_token_price) 都处理了, 但 _settings_dict (GET) 漏了两行,
导致管理后台设置页两个 1080P 单价输入框显示空白。

实际影响
- DB 值对 (51 / 31), 计费走 _get_token_price 直接读 DB, 计费一直正确
- 前端 SettingsPage fetchSettings 用 setSettings(data) 覆盖,
  GET 返回缺字段 -> state 变 undefined -> 输入框显示空
- 管理员点保存: undefined 被 JSON.stringify 省略 -> PUT body 不含
  这两字段 -> serializer validated_data 里没有 -> DB 未改
- 所以目前"巧合安全", 但风险: 管理员在空输入框填数字后清空,
  Number("") = 0 会覆盖 DB, 把单价刷成 0

修复
- backend/apps/generation/views.py _settings_dict() 加两行返回
  base_token_price_1080p / base_token_price_1080p_video
- 前端 GET 后 state 直接拿到 51 / 31, 输入框自动显示, 不依赖"巧合"

回归测试 (backend/tests/test_1080p_api.py)
- 新增 TestAdminSettingsResponse.test_get_returns_all_token_price_fields
  断言 GET /admin/settings 返回 6 个 token_price 字段全齐
- 失败消息明示: "缺字段会导致前端输入框显示空" 以防以后再漏

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
seaislee1209 2026-04-24 19:09:55 +08:00
parent 13440f2709
commit ecdb9cb471
2 changed files with 35 additions and 0 deletions

View File

@ -1907,6 +1907,8 @@ def _settings_dict(config):
'base_token_price_video': float(config.base_token_price_video), 'base_token_price_video': float(config.base_token_price_video),
'base_token_price_fast': float(config.base_token_price_fast), 'base_token_price_fast': float(config.base_token_price_fast),
'base_token_price_fast_video': float(config.base_token_price_fast_video), 'base_token_price_fast_video': float(config.base_token_price_fast_video),
'base_token_price_1080p': float(config.base_token_price_1080p),
'base_token_price_1080p_video': float(config.base_token_price_1080p_video),
'announcement': config.announcement, 'announcement': config.announcement,
'announcement_enabled': config.announcement_enabled, 'announcement_enabled': config.announcement_enabled,
'max_desktop_sessions': config.max_desktop_sessions, 'max_desktop_sessions': config.max_desktop_sessions,

View File

@ -127,5 +127,38 @@ class TestVideoGenerateResolution(TestCase):
self.assertNotEqual(body.get('error'), 'invalid_resolution') self.assertNotEqual(body.get('error'), 'invalid_resolution')
class TestAdminSettingsResponse(TestCase):
"""GET /api/v1/admin/settings 必须返回所有 token_price 字段,
以防 v0.19.0 那种"字段在 serializer 里加了、但 _settings_dict 漏了"的回归"""
def setUp(self):
QuotaConfig.objects.get_or_create(pk=1)
self.admin = User.objects.create_user(
username='test_admin_settings',
email='test_admin_settings@example.com',
password='testpass123',
is_staff=True,
is_superuser=True,
)
self.client = APIClient()
self.client.force_authenticate(user=self.admin)
def test_get_returns_all_token_price_fields(self):
"""GET 返回 4 档单价(全部分辨率 + 是否含视频),缺一不可 — 缺字段会导致前端输入框显示空。"""
resp = self.client.get('/api/v1/admin/settings')
self.assertEqual(resp.status_code, 200)
body = resp.json()
for field in (
'base_token_price',
'base_token_price_video',
'base_token_price_fast',
'base_token_price_fast_video',
'base_token_price_1080p',
'base_token_price_1080p_video',
):
self.assertIn(field, body, f'GET /admin/settings response missing {field!r} — 前端这个输入框会显示空')
self.assertIsInstance(body[field], (int, float), f'{field} 应该是数字类型')
if __name__ == '__main__': if __name__ == '__main__':
unittest.main(verbosity=2) unittest.main(verbosity=2)