diff --git a/api/api/products/admin.py b/api/api/products/admin.py index cb54fb3..5c1da1c 100644 --- a/api/api/products/admin.py +++ b/api/api/products/admin.py @@ -12,6 +12,7 @@ admin.site.register(ScanData) admin.site.register(EstorArchiveRecord) admin.site.register(Job) admin.site.register(ConsumerInfo) +admin.site.register(FrameLabel) class AuthTokenAdmin(admin.ModelAdmin): search_fields = ['token'] diff --git a/api/api/products/migrations/0095_auto_20250215_1138.py b/api/api/products/migrations/0095_auto_20250215_1138.py new file mode 100644 index 0000000..c5afec9 --- /dev/null +++ b/api/api/products/migrations/0095_auto_20250215_1138.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.25 on 2025-02-15 11:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('products', '0094_scandata_labels'), + ] + + operations = [ + migrations.CreateModel( + name='FrameLabel', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('oss_path', models.TextField(db_index=True, unique=True, verbose_name='OSS路径')), + ('labels', models.TextField(verbose_name='标签')), + ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建日期')), + ('update_time', models.DateTimeField(auto_now=True, verbose_name='更新日期')), + ], + ), + migrations.AlterField( + model_name='scandata', + name='labels', + field=models.TextField(blank=True, default='', verbose_name='标签'), + ), + ] diff --git a/api/api/products/models.py b/api/api/products/models.py index f5f8ad6..eb8a72b 100644 --- a/api/api/products/models.py +++ b/api/api/products/models.py @@ -401,3 +401,12 @@ class CameraRule(models.Model): def __str__(self): return self.name + +class FrameLabel(models.Model): + oss_path = models.TextField(verbose_name="OSS路径", unique=True, db_index=True) + labels = models.TextField(verbose_name="标签") + create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建日期") + update_time = models.DateTimeField(auto_now=True, verbose_name="更新日期") + + def __str__(self): + return self.oss_path diff --git a/api/api/products/views.py b/api/api/products/views.py index d60f06b..3fd7425 100644 --- a/api/api/products/views.py +++ b/api/api/products/views.py @@ -1800,3 +1800,68 @@ class CameraFrameView(BaseView): key = f'{date}/{phone_model}-{session_id}-{seq_num}-{filename}' oss_put(key, filebody, bucket=settings.FRAMES_BUCKET) return JsonResponse({}) + +class FramesView(BaseView): + name = 'frames' + auth_check = 'admin' + + def get(self, request): + start = request.GET.get('start', 0) + end = request.GET.get('end', 100) + ret = oss_list(bucket=settings.FRAMES_BUCKET) + start = int(start) + end = int(end) + frames = [] + for frame in ret[start:end]: + fo = FrameLabel.objects.filter(oss_path=frame).first() + if fo: + frames.append({ + 'path': frame, + 'labels': fo.labels.split(','), + }) + else: + frames.append({ + 'path': frame, + 'labels': [], + }) + return JsonResponse({ + 'frames': frames, + 'total': len(ret), + 'start': start, + 'end': end, + }) +class FrameView(BaseView): + name = 'frame' + + def get(self, request): + path = request.GET.get('path') + return HttpResponse(oss_get(path, bucket=settings.FRAMES_BUCKET), + content_type='image/jpeg') + +class DeleteFrameView(BaseView): + name = 'delete-frame' + auth_check = 'admin' + + def post(self, request): + path = request.data.get('path') + oss_delete(path, bucket=settings.FRAMES_BUCKET) + FrameLabel.objects.filter(oss_path=path).delete() + return JsonResponse({}) + +class LabelFrameView(BaseView): + name = 'label-frame' + auth_check = 'admin' + + def post(self, request): + path = request.data.get('path') + label = request.data.get('label') + fo, _ = FrameLabel.objects.get_or_create(oss_path=path) + if fo.labels.split(',').count(label) == 0: + fo.labels = fo.labels + ',' + label if fo.labels else label + else: + fo.labels = ','.join([x for x in fo.labels.split(',') if x != label]) + fo.save() + return JsonResponse({ + 'ok': True, + 'id': fo.id, + }) \ No newline at end of file