From 653f057b517e6fd3e0290f59e28f5c59dd3e3cef Mon Sep 17 00:00:00 2001 From: pmc <740076875@qq.com> Date: Thu, 7 May 2026 17:42:36 +0800 Subject: [PATCH] =?UTF-8?q?feat(01-02):=20aiapp/admin.py=20=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=20CredentialSlotAdmin=EF=BC=88=E8=84=B1=E6=95=8F=20+?= =?UTF-8?q?=20=E5=8D=95=E4=BE=8B=E6=96=B0=E5=A2=9E=20+=20=E7=A6=81?= =?UTF-8?q?=E5=88=A0=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - import 追加 CredentialSlot 与 common.utils.mask_token - 新增 CredentialSlotAdmin(覆盖 CRED-02): - list_display 含计算字段 access_token_masked(仅末 4 位明文) - fieldsets 分「凭据信息」明文可写 + 「元数据」updated_at 只读折叠 - has_add_permission 已存在记录时返回 False(隐藏增加按钮) - has_delete_permission 永远返回 False(含批量动作) - 不修改既有 BotAdmin / ChatMessage 注册块 --- qy_lty/aiapp/admin.py | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/qy_lty/aiapp/admin.py b/qy_lty/aiapp/admin.py index fb909f1..0a8851d 100644 --- a/qy_lty/aiapp/admin.py +++ b/qy_lty/aiapp/admin.py @@ -1,6 +1,7 @@ from django.contrib import admin -from .models import Bot, ChatMessage +from .models import Bot, ChatMessage, CredentialSlot +from common.utils import mask_token @admin.register(Bot) class BotAdmin(admin.ModelAdmin): @@ -12,3 +13,41 @@ class BotAdmin(admin.ModelAdmin): class BotAdmin(admin.ModelAdmin): list_display = ('id', 'user', 'bot', 'message', 'timestamp', 'sender', 'message_type') search_fields = ('id', 'user', 'bot', 'message', 'timestamp', 'sender', 'message_type') + + +@admin.register(CredentialSlot) +class CredentialSlotAdmin(admin.ModelAdmin): + """通用凭据槽位 Admin(单例)— Milestone v1.0 / Phase 1 + + UX 行为: + - 列表 / 查看态 access_token 显示末 4 位掩码 + - 编辑表单 access_token 明文(运营录入需要) + - 已存在记录时隐藏「增加」按钮 + - 永远禁止删除(防运营误操作丢失单例) + """ + + list_display = ('id', 'app_id', 'access_token_masked', 'updated_at') + readonly_fields = ('updated_at',) + + fieldsets = ( + ('凭据信息', { + 'fields': ('app_id', 'access_token'), + 'description': '第三方服务商分配的 APP ID + Access Token;保存后立即对手机端 / 设备端生效', + }), + ('元数据', { + 'fields': ('updated_at',), + 'classes': ('collapse',), + }), + ) + + def access_token_masked(self, obj): + return mask_token(obj.access_token) + access_token_masked.short_description = 'Access Token (脱敏)' + + def has_add_permission(self, request): + # 已存在记录时隐藏「增加」,配合 has_delete_permission 强制单例 + return not CredentialSlot.objects.exists() + + def has_delete_permission(self, request, obj=None): + # 永远禁止删除(含批量动作) + return False