perf: group_stats

pull/15846/head
feng 2025-08-14 11:38:57 +08:00 committed by feng626
parent 24f7946b7b
commit 4810eae725
4 changed files with 17 additions and 11 deletions

View File

@ -11,7 +11,6 @@ from assets.models import Asset, Platform
from common.permissions import IsValidLicense from common.permissions import IsValidLicense
from common.utils import lazyproperty from common.utils import lazyproperty
from rbac.permissions import RBACPermission from rbac.permissions import RBACPermission
from reports.api.assets.base import group_stats
from reports.mixins import DateRangeMixin from reports.mixins import DateRangeMixin
__all__ = ['AssetStatisticApi'] __all__ = ['AssetStatisticApi']
@ -52,18 +51,26 @@ class AssetStatisticApi(DateRangeMixin, APIView):
) )
type_category_map = { type_category_map = {
d['label']: str(d['category'].label) d['value']: str(d['category'].label)
for d in AllTypes.types() for d in AllTypes.types()
} }
by_type = group_stats( category_type_ids = defaultdict(lambda: defaultdict(set))
qs, 'type', 'platform__type', all_type_dict, for _id, tp, category in (qs.select_related('platform')
) .values_list('id', 'platform__type', 'platform__category')):
category_label = type_category_map.get(tp, 'Other')
category_type_ids[category_label][tp].add(_id)
by_type_category = defaultdict(list) by_type_category = defaultdict(list)
for item in by_type: for k, v in category_type_ids.items():
category = type_category_map.get(item['label'], 'Other') by_type_category[k] = [
by_type_category[category].append(item) {
'label': all_type_dict.get(tp, tp),
'type': tp,
'total': len(_ids),
}
for tp, _ids in v.items()
]
sorted_category_assets = OrderedDict() sorted_category_assets = OrderedDict()
desired_order = [str(i['label']) for i in AllTypes.categories()] desired_order = [str(i['label']) for i in AllTypes.categories()]

View File

@ -4,10 +4,8 @@
{% if INTERFACE.footer_content %} {% if INTERFACE.footer_content %}
<style> <style>
.markdown-footer{ .markdown-footer{
position: absolute;
left: 50%; left: 50%;
bottom: 0; bottom: 0;
transform: translateX(-50%);
max-width: 520px; max-width: 520px;
width: calc(100% - 40px); width: calc(100% - 40px);
padding: 8px 0; padding: 8px 0;

View File

@ -113,6 +113,7 @@ class LoginFrom(TextChoices):
RT = 'RT', 'RDP Terminal' RT = 'RT', 'RDP Terminal'
WT = 'WT', 'Web Terminal' WT = 'WT', 'Web Terminal'
DT = 'DT', 'DB Terminal' DT = 'DT', 'DB Terminal'
VT = 'VT', 'VNC Terminal'
@classmethod @classmethod
def as_dict(cls): def as_dict(cls):

View File

@ -124,7 +124,7 @@ class Migration(migrations.Migration):
('input', models.CharField(db_index=True, max_length=128, verbose_name='Input')), ('input', models.CharField(db_index=True, max_length=128, verbose_name='Input')),
('output', models.CharField(blank=True, max_length=1024, verbose_name='Output')), ('output', models.CharField(blank=True, max_length=1024, verbose_name='Output')),
('session', models.CharField(db_index=True, max_length=36, verbose_name='Session')), ('session', models.CharField(db_index=True, max_length=36, verbose_name='Session')),
('risk_level', models.SmallIntegerField(choices=[(0, 'Accept'), (4, 'Warning'), (5, 'Reject'), (6, 'Review & Reject'), (7, 'Review & Accept'), (8, 'Review & Cancel')], db_index=True, default=0, verbose_name='Risk level')), ('risk_level', models.SmallIntegerField(choices=[(0, 'Accept'), (4, 'Warning'), (5, 'Reject'), (6, 'Review & Reject'), (7, 'Review & Accept'), (8, 'Review & Cancel')], db_index=True, default=0, verbose_name='Action')),
('timestamp', models.IntegerField(db_index=True)), ('timestamp', models.IntegerField(db_index=True)),
], ],
options={ options={