feat: update card views/serializers and admin sidebar
All checks were successful
Build and Deploy LTY / build-and-deploy (push) Successful in 47m12s
All checks were successful
Build and Deploy LTY / build-and-deploy (push) Successful in 47m12s
- Add new card API endpoints and serializers - Update sidebar navigation - Update claude settings permissions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5483c69ba9
commit
55ca2cbdaf
@ -136,7 +136,24 @@
|
||||
"Bash(curl -s \"http://127.0.0.1:8000/api/device/devices/bind_status/?mac_address=FF:FF:FF:FF:FF:FF\")",
|
||||
"Bash(curl -s -X POST http://127.0.0.1:8000/api/device/user-devices/bind/ -H \"Content-Type: application/json\" -H \"Authorization: Bearer 026e2157-404a-45e9-ad97-3f79e8a31a09\" -d \"{\"\"mac_address\"\": \"\"AA:BB:CC:DD:EE:01\"\"}\")",
|
||||
"Bash(curl -s http://127.0.0.1:8000/api/device/user-devices/ -H \"Authorization: Bearer 026e2157-404a-45e9-ad97-3f79e8a31a09\")",
|
||||
"Bash(curl -s -X DELETE http://127.0.0.1:8000/api/device/user-devices/7/ -H \"Authorization: Bearer 026e2157-404a-45e9-ad97-3f79e8a31a09\" -w \"\\\\nHTTP_CODE: %{http_code}\")"
|
||||
"Bash(curl -s -X DELETE http://127.0.0.1:8000/api/device/user-devices/7/ -H \"Authorization: Bearer 026e2157-404a-45e9-ad97-3f79e8a31a09\" -w \"\\\\nHTTP_CODE: %{http_code}\")",
|
||||
"Bash(curl -s -v \"https://qy-lty.airlabs.art/api/device/devices/bind_status/?mac_address=test\")",
|
||||
"Bash(curl -s \"https://qy-lty.airlabs.art/api/device/devices/bind_status/?mac_address=test\")",
|
||||
"Bash(curl -s \"https://qy-lty.airlabs.art/api/device/\")",
|
||||
"Bash(curl -s -o /dev/null -w \"%{http_code}\" \"https://qy-lty.airlabs.art/api/device/devices/register/\")",
|
||||
"Bash(curl -s -X POST \"https://qy-lty.airlabs.art/api/device/devices/register/\" -H \"Content-Type: application/json\" -d '{\"\"mac_address\"\":\"\"test\"\"}')",
|
||||
"Bash(curl -s -v \"https://qy-lty.airlabs.art/api/device/devices/nonexistent_action_xyz/\")",
|
||||
"Bash(curl -s \"https://qy-lty.airlabs.art/swagger/?format=openapi\")",
|
||||
"Bash(curl -s --connect-timeout 5 \"http://localhost:8000/api/device/devices/bind_status/?mac_address=test\")",
|
||||
"Bash(curl -s \"http://localhost:8000/api/device/devices/bind_status/\")",
|
||||
"Bash(curl -s -X POST \"http://localhost:8000/api/device/devices/register/\" -H \"Content-Type: application/json\" -d '{\"\"mac_address\"\":\"\"test\"\"}')",
|
||||
"Bash(curl -s \"http://localhost:8000/api/device/devices/bind_status/?mac_address=test\")",
|
||||
"Bash(grep -E \"\\(layout|page\\\\.tsx$\\)\")",
|
||||
"Bash(grep -E \"\\\\.\\(tsx|ts\\)$\")",
|
||||
"Bash(python -c \"from card.serializers import MobileClothingTemplateSerializer; print\\(''Serializer OK''\\)\")",
|
||||
"Bash(python -c \"from card.views import MobileClothingListView; print\\(''View OK''\\)\")",
|
||||
"Bash(python -c \"from card.urls import urlpatterns; print\\(f''URLs OK, {len\\(urlpatterns\\)} routes''\\)\")",
|
||||
"Bash(DJANGO_SETTINGS_MODULE=qy_lty.settings python -c \"import django; django.setup\\(\\); from card.serializers import MobileClothingTemplateSerializer; print\\(''Serializer OK''\\); from card.views import MobileClothingListView; print\\(''View OK''\\); from card.urls import urlpatterns; print\\(f''URLs OK, {len\\(urlpatterns\\)} routes''\\)\")"
|
||||
],
|
||||
"additionalDirectories": [
|
||||
"C:\\Users\\admin\\.claude"
|
||||
|
||||
@ -107,8 +107,8 @@ export function Sidebar() {
|
||||
|
||||
return (
|
||||
<div className="flex h-screen border-r bg-gradient-to-b from-white to-gray-50 shadow-md">
|
||||
<div className="flex w-full flex-col space-y-4 p-4">
|
||||
<div className="flex h-16 items-center px-4 py-2">
|
||||
<div className="flex w-full flex-col p-4">
|
||||
<div className="flex h-16 items-center px-4 py-2 shrink-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="h-8 w-8 rounded-full bg-gradient-to-br from-pink-500 to-purple-600 flex items-center justify-center">
|
||||
<Sparkles className="h-4 w-4 text-white" />
|
||||
@ -122,7 +122,7 @@ export function Sidebar() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<div className="space-y-1.5 flex-1 overflow-y-auto mt-4">
|
||||
{/* 仪表盘 - 所有角色都可见 */}
|
||||
<Button
|
||||
variant={pathname === "/" ? "default" : "ghost"}
|
||||
@ -177,7 +177,7 @@ export function Sidebar() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="mt-auto pt-4">
|
||||
<div className="shrink-0 pt-4">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="w-full justify-start hover:bg-red-50 hover:text-red-600 transition-colors"
|
||||
|
||||
@ -402,6 +402,49 @@ class CategoryTemplateSerializer(CardTemplateDetailSerializer):
|
||||
return representation
|
||||
|
||||
|
||||
class MobileClothingTemplateSerializer(serializers.ModelSerializer):
|
||||
"""手机端服装模板序列化器 - 只返回已发布服装的必要字段"""
|
||||
card_type_display = serializers.SerializerMethodField()
|
||||
rarity_display = serializers.SerializerMethodField()
|
||||
status_display = serializers.SerializerMethodField()
|
||||
image_url = serializers.URLField(source='image', read_only=True)
|
||||
active_cards_count = serializers.SerializerMethodField()
|
||||
attributes = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = CardTemplate
|
||||
fields = [
|
||||
'id', 'name', 'description',
|
||||
'card_type', 'card_type_display',
|
||||
'rarity', 'rarity_display',
|
||||
'image_url',
|
||||
'status', 'status_display',
|
||||
'published_at',
|
||||
'active_cards_count',
|
||||
'attributes',
|
||||
]
|
||||
|
||||
def get_card_type_display(self, obj):
|
||||
return obj.get_card_type_display()
|
||||
|
||||
def get_rarity_display(self, obj):
|
||||
return obj.get_rarity_display()
|
||||
|
||||
def get_status_display(self, obj):
|
||||
return obj.get_status_display()
|
||||
|
||||
def get_active_cards_count(self, obj):
|
||||
return obj.cards.filter(status='active').count()
|
||||
|
||||
def get_attributes(self, obj):
|
||||
try:
|
||||
if hasattr(obj, 'clothing_attrs'):
|
||||
return ClothingAttributesSerializer(obj.clothing_attrs).data
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
# 带有专有属性的卡牌详情序列化器
|
||||
class CategoryCardDetailSerializer(CardDetailSerializer):
|
||||
"""Card detail serializer with category-specific attributes"""
|
||||
|
||||
@ -11,5 +11,6 @@ urlpatterns = [
|
||||
path('', include(router.urls)),
|
||||
path('user/cards/', views.UserCardListView.as_view(), name='user-cards'),
|
||||
path('category/<str:category>/', views.CategoryCardTemplateListView.as_view(), name='category-templates'),
|
||||
path('mobile/clothing/', views.MobileClothingListView.as_view(), name='mobile-clothing-list'),
|
||||
]
|
||||
|
||||
|
||||
@ -24,10 +24,10 @@ import csv
|
||||
from .models import CardTemplate, Card, CardBatch, CardUsageLog
|
||||
from .serializers import (
|
||||
CardTemplateSerializer, CardTemplateDetailSerializer,
|
||||
CardSerializer, CardDetailSerializer, CardBatchSerializer, CardUsageLogSerializer,
|
||||
CardSerializer, CardDetailSerializer, CardBatchSerializer, CardUsageLogSerializer,
|
||||
CardScanSerializer, CardUseSerializer, CardBatchGenerateSerializer,
|
||||
CardTemplatePublishSerializer, CardBatchPublishSerializer, CardBatchManufactureSerializer,
|
||||
CategoryTemplateSerializer, CategoryCardDetailSerializer,
|
||||
CategoryTemplateSerializer, CategoryCardDetailSerializer, MobileClothingTemplateSerializer,
|
||||
ClothingAttributesSerializer, PropAttributesSerializer, SongAttributesSerializer,
|
||||
DanceAttributesSerializer, FurnitureAttributesSerializer, DecorationAttributesSerializer
|
||||
)
|
||||
@ -1020,3 +1020,66 @@ class CategoryCardTemplateListView(generics.ListAPIView):
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""实现分页的列表查询"""
|
||||
return super().list(request, *args, **kwargs)
|
||||
|
||||
|
||||
class MobileClothingListView(generics.ListAPIView):
|
||||
"""
|
||||
手机端服装列表接口
|
||||
|
||||
仅返回已发布的服装模板,供手机端展示。
|
||||
支持按稀有度、类型筛选和关键词搜索。
|
||||
"""
|
||||
serializer_class = MobileClothingTemplateSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
authentication_classes = [RedisTokenAuthentication]
|
||||
tags = ['手机端']
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = CardTemplate.objects.filter(
|
||||
category='clothing',
|
||||
status='published',
|
||||
).order_by('-published_at')
|
||||
|
||||
# 按稀有度筛选
|
||||
rarity = self.request.query_params.get('rarity')
|
||||
if rarity:
|
||||
queryset = queryset.filter(rarity=rarity)
|
||||
|
||||
# 按类型筛选
|
||||
card_type = self.request.query_params.get('card_type')
|
||||
if card_type:
|
||||
queryset = queryset.filter(card_type=card_type)
|
||||
|
||||
# 关键词搜索
|
||||
search = self.request.query_params.get('search')
|
||||
if search:
|
||||
queryset = queryset.filter(name__icontains=search)
|
||||
|
||||
return queryset
|
||||
|
||||
@swagger_schema(
|
||||
responses={
|
||||
200: openapi.Response('查询成功', schema=openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT,
|
||||
properties={
|
||||
'count': openapi.Schema(type=openapi.TYPE_INTEGER, description='总数'),
|
||||
'next': openapi.Schema(type=openapi.TYPE_STRING, description='下一页URL', nullable=True),
|
||||
'previous': openapi.Schema(type=openapi.TYPE_STRING, description='上一页URL', nullable=True),
|
||||
'results': openapi.Schema(
|
||||
type=openapi.TYPE_ARRAY,
|
||||
items=openapi.Schema(type=openapi.TYPE_OBJECT, description='服装模板'),
|
||||
),
|
||||
},
|
||||
)),
|
||||
},
|
||||
operation_description="获取已发布的服装列表(手机端专用)",
|
||||
tags=['手机端'],
|
||||
manual_parameters=[
|
||||
openapi.Parameter('rarity', openapi.IN_QUERY, description="按稀有度筛选 (common/uncommon/rare/epic/legendary/limited)", type=openapi.TYPE_STRING, required=False),
|
||||
openapi.Parameter('card_type', openapi.IN_QUERY, description="按类型筛选 (regular/seasonal/event)", type=openapi.TYPE_STRING, required=False),
|
||||
openapi.Parameter('search', openapi.IN_QUERY, description="按名称搜索", type=openapi.TYPE_STRING, required=False),
|
||||
],
|
||||
security=[{'Bearer': []}]
|
||||
)
|
||||
def list(self, request, *args, **kwargs):
|
||||
return super().list(request, *args, **kwargs)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user