part of sort

This commit is contained in:
Kseninia Mikhaylova 2024-08-22 14:13:12 +03:00
parent 6dbac8bd4b
commit 664f081b9f
7 changed files with 85 additions and 24 deletions

View File

@ -39,6 +39,7 @@ ALLOWED_HOSTS = [
CORS_ALLOWED_ORIGINS = [ CORS_ALLOWED_ORIGINS = [
"http://localhost", "http://localhost",
"http://localhost:3000", "http://localhost:3000",
"http://localhost:3001",
"http://192.168.106.234:3000", "http://192.168.106.234:3000",
"https://toinv.svs-tech.pro", "https://toinv.svs-tech.pro",
] ]

View File

@ -29,11 +29,17 @@ class TgItemSerializer(serializers.ModelSerializer):
class TgStatItemSerializer(serializers.Serializer): class TgStatItemSerializer(serializers.Serializer):
location = serializers.SerializerMethodField() location = serializers.SerializerMethodField(required=False)
inv_count = serializers.IntegerField() inv_count = serializers.IntegerField()
tmc = serializers.SerializerMethodField() tmc = serializers.SerializerMethodField()
def get_location(self, obj): def get_location(self, obj):
if not obj.get("location__parent"):
return None
if isinstance(obj.get("location__parent"), list):
queryset = Territory.objects.filter(id__in=obj.get("location__parent"))
serializer = TerritorySerializer(queryset, many=True)
else:
queryset = Territory.objects.get(id=obj.get("location__parent")) queryset = Territory.objects.get(id=obj.get("location__parent"))
serializer = TerritorySerializer(queryset) serializer = TerritorySerializer(queryset)
@ -45,7 +51,6 @@ class TgStatItemSerializer(serializers.Serializer):
.values("tmc__name") .values("tmc__name")
.annotate(count=Count("id")) .annotate(count=Count("id"))
) )
logger.info(queryset)
serializer = TmcElementSerializer(queryset, many=True) serializer = TmcElementSerializer(queryset, many=True)
return serializer.data return serializer.data

View File

@ -129,6 +129,7 @@ class TmcStatViewset(viewsets.ViewSet):
http_method_names = ["get"] http_method_names = ["get"]
def list(self, request): def list(self, request):
if 'type' in request.query_params and request.query_params['type'] == 'location':
queryset = ( queryset = (
TgItem.objects.all() TgItem.objects.all()
.values("location__parent") .values("location__parent")
@ -140,6 +141,19 @@ class TmcStatViewset(viewsets.ViewSet):
tmc=ArrayAgg("tmc"), tmc=ArrayAgg("tmc"),
) )
) )
logger.info(queryset) else:
queryset = (
TgItem.objects.all()
.values("tmc__tmc_id")
.annotate(
inv_count=Count("location__parent"),
tmc_count=Count("tmc__tmc_id", distinct=True)
)
.annotate(
location__parent=ArrayAgg("location__parent"),
tmc=ArrayAgg("tmc"),
)
)
# logger.info(queryset)
serializer = TgStatItemSerializer(queryset, many=True) serializer = TgStatItemSerializer(queryset, many=True)
return Response(serializer.data) return Response(serializer.data)

View File

@ -10,10 +10,12 @@
"@nuxt/image": "^1.7.0", "@nuxt/image": "^1.7.0",
"@nuxt/ui": "^2.16.0", "@nuxt/ui": "^2.16.0",
"@pinia/nuxt": "^0.5.1", "@pinia/nuxt": "^0.5.1",
"chart.js": "^3.9.1",
"nuxt": "^3.11.2", "nuxt": "^3.11.2",
"nuxt-svgo": "^4.0.1", "nuxt-svgo": "^4.0.1",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"vue": "^3.4.27", "vue": "^3.4.27",
"vue-chart-3": "^3.1.8",
"vue-router": "^4.3.2", "vue-router": "^4.3.2",
"vue3-telegram-login": "^1.1.0", "vue3-telegram-login": "^1.1.0",
"yup": "^1.4.0" "yup": "^1.4.0"
@ -5114,6 +5116,12 @@
"node": ">=0.8.0" "node": ">=0.8.0"
} }
}, },
"node_modules/chart.js": {
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz",
"integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==",
"license": "MIT"
},
"node_modules/chokidar": { "node_modules/chokidar": {
"version": "3.6.0", "version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
@ -12545,6 +12553,22 @@
"ufo": "^1.5.3" "ufo": "^1.5.3"
} }
}, },
"node_modules/vue-chart-3": {
"version": "3.1.8",
"resolved": "https://registry.npmjs.org/vue-chart-3/-/vue-chart-3-3.1.8.tgz",
"integrity": "sha512-zX5ajjQi/PocEqLETlej3vp92q/tnI/Fvu2RVb++Kap8qOrXu6PXCpodi73BFrWzEGZIAnqoUxC3OIkRWD657g==",
"license": "MIT",
"dependencies": {
"@vue/runtime-core": "latest",
"@vue/runtime-dom": "latest",
"csstype": "latest",
"lodash-es": "latest"
},
"peerDependencies": {
"chart.js": "=> ^3.1.0",
"vue": ">= 3"
}
},
"node_modules/vue-devtools-stub": { "node_modules/vue-devtools-stub": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/vue-devtools-stub/-/vue-devtools-stub-0.1.0.tgz", "resolved": "https://registry.npmjs.org/vue-devtools-stub/-/vue-devtools-stub-0.1.0.tgz",

View File

@ -19,7 +19,9 @@
"vue": "^3.4.27", "vue": "^3.4.27",
"vue-router": "^4.3.2", "vue-router": "^4.3.2",
"vue3-telegram-login": "^1.1.0", "vue3-telegram-login": "^1.1.0",
"yup": "^1.4.0" "yup": "^1.4.0",
"chart.js": "^3.9.1",
"vue-chart-3": "^3.1.8"
}, },
"devDependencies": { "devDependencies": {
"sass": "^1.77.2" "sass": "^1.77.2"

View File

@ -1,5 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
const data = await apiCall<RootObject[]>(`stat/`, 'get') const isOrg = ref(true)
const data = ref([] as RootObject[])
data.value = await apiCall<RootObject[]>(`stat/?type=location`, 'get')
interface RootObject { interface RootObject {
location: Location; location: Location;
inv_count: number; inv_count: number;
@ -13,17 +16,35 @@ interface Location {
id: number; id: number;
name: string; name: string;
} }
const getData = async () => {
isOrg.value = !isOrg.value
data.value = []
data.value = await apiCall<RootObject[]>(`stat/${isOrg.value == true ? '?type=location' : ''}`, 'get')
}
</script> </script>
<template> <template>
<div class="grid grid-cols-12 gap-4"> <div class="grid grid-cols-12 gap-4">
<div class="col-span-12 page-header"> <div class="col-span-12 page-header">
<h1>Результаты инвентаризации</h1> <h1>Результаты инвентаризации</h1>
</div> </div>
<UCard v-for="item in data" class="col-span-4"> <div class="col-span-12">
<UButtonGroup>
<UButton :disabled="isOrg" @click="getData">По организациям</UButton>
<UButton :disabled="!isOrg" @click="getData">По продуктам</UButton>
</UButtonGroup>
</div>
<UCard v-for="item in data" class="col-span-4" v-if="data && isOrg">
<template #header> <template #header>
{{ item.location.name }} <UBadge>{{ item.inv_count }}</UBadge> {{ item.location.name }} <UBadge>{{ item.inv_count }}</UBadge>
</template> </template>
<UTable :rows="item.tmc" /> <UTable :rows="item.tmc" />
</UCard> </UCard>
<UCard v-for="item in data" class="col-span-6" v-if="data && !isOrg">
<template #header>
{{ item.tmc[0].tmc__name }} <UBadge>{{ item.tmc[0].count }}</UBadge>
</template>
<UTable :rows="item.location" />
</UCard>
</div> </div>
</template> </template>

6
package-lock.json generated
View File

@ -1,6 +0,0 @@
{
"name": "to_inventory",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}