This commit is contained in:
aarizona 2024-05-30 10:22:31 +03:00
parent 659e1ee439
commit c2edb2fe2a
17 changed files with 112 additions and 38 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
.idea/ .idea/
.vscode/ .vscode/
.venv/

View File

@ -1,18 +1,44 @@
from rest_framework import serializers from rest_framework import serializers
from .models import Element, InventoryItem, Partner from .models import Element, InventoryItem, Partner
import logging
logger = logging.getLogger("root")
class PartnerSerializer(serializers.ModelSerializer): class PartnerSerializer(serializers.ModelSerializer):
total_inventory = serializers.SerializerMethodField()
class Meta: class Meta:
model = Partner model = Partner
fields = ["id", "external_id"] fields = ["id", "external_id", "name", "total_inventory"]
def get_total_inventory(self, instance):
return InventoryItem.objects.filter(partner=instance).count()
class InventorySerializer(serializers.ModelSerializer): class InventorySerializer(serializers.ModelSerializer):
partner_name = serializers.CharField(source="partner.name", read_only=True)
total_elements = serializers.SerializerMethodField()
class Meta: class Meta:
model = InventoryItem model = InventoryItem
fields = ["id", "partner"] fields = ["id", "partner", "partner_name", "name", "total_elements"]
def get_total_elements(self, instance):
return Element.objects.filter(inventory=instance).count()
class ElementSerializer(serializers.ModelSerializer): class ElementSerializer(serializers.ModelSerializer):
inventory_name = serializers.CharField(source="inventory.name", read_only=True)
class Meta: class Meta:
model = Element model = Element
fields = ["id", "external_id", "element_id", "photo", "additional_text", "inventory"] fields = [
"id",
"external_id",
"element_id",
"photo",
"additional_text",
"inventory",
"inventory_name",
]

View File

@ -1,4 +1,3 @@
import urllib
import requests import requests
from django.conf import settings from django.conf import settings
@ -24,13 +23,6 @@ class PartnerViewSet(viewsets.ModelViewSet):
queryset = Partner.objects.all() queryset = Partner.objects.all()
serializer_class = PartnerSerializer serializer_class = PartnerSerializer
def create(self, validated_data):
logger.info("create")
super().create(**validated_data)
def get(self, request, **kwargs):
logger.info("get")
@action(detail=False, methods=["get"], url_path=r"external") @action(detail=False, methods=["get"], url_path=r"external")
def get_remote_partners(self, request): def get_remote_partners(self, request):
params = { params = {
@ -72,7 +64,7 @@ class InventoryItemViewSet(viewsets.ModelViewSet):
def get_queryset(self): def get_queryset(self):
queryset = InventoryItem.objects.all() queryset = InventoryItem.objects.all()
partner = self.request.query_params.get('partner_id') partner = self.request.query_params.get("partner_id")
if partner is not None: if partner is not None:
queryset = queryset.filter(partner=partner) queryset = queryset.filter(partner=partner)
return queryset return queryset
@ -88,7 +80,7 @@ class ElementViewSet(viewsets.ModelViewSet):
def get_queryset(self): def get_queryset(self):
queryset = Element.objects.all() queryset = Element.objects.all()
inventory = self.request.query_params.get('inventory_id') inventory = self.request.query_params.get("inventory_id")
if inventory is not None: if inventory is not None:
queryset = queryset.filter(inventory=inventory) queryset = queryset.filter(inventory=inventory)
return queryset return queryset
@ -105,7 +97,8 @@ class ElementViewSet(viewsets.ModelViewSet):
# check if inventory exist # check if inventory exist
if ( if (
"inventory" in data "inventory"
in data
# and InventoryItem.objects.filter(id=data["inventory"]).exists() # and InventoryItem.objects.filter(id=data["inventory"]).exists()
): ):
inventory_object = InventoryItem.objects.get(id=data["inventory"]) inventory_object = InventoryItem.objects.get(id=data["inventory"])

4
dev.sh
View File

@ -1,3 +1,3 @@
#!/bin/bash #!/bin/bash
xterm -title "To Invetory FRONT" -e "cd front && npm run dev"& x-terminal-emulator -title "To Invetory FRONT" -e "cd front && npm run dev"&
xterm -title "To Invetory BACK" -e "poetry run task server" x-terminal-emulator -title "To Invetory BACK" -e "poetry run task server"

6
front/app.config.ts Normal file
View File

@ -0,0 +1,6 @@
export default defineAppConfig({
ui: {
primary: 'pink',
gray: 'cool'
}
})

View File

@ -1,13 +1,17 @@
<script setup lang="ts"> <script setup lang="ts">
import 'assets/main.scss' import 'assets/main.scss'
import Logo from 'assets/logo.svg'
</script> </script>
<template> <template>
<div class="container"> <div class="container">
<div class="header"> <div class="header">
HEADER <div class="logo">
<Logo />
</div>
<NuxtLink to="/">Инвентаризация</NuxtLink>
</div> </div>
<div class="sidebar"> <div class="sidebar">
<Sidebar/> <Sidebar />
</div> </div>
<div class="content"> <div class="content">
<NuxtPage /> <NuxtPage />

1
front/assets/logo.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="currentColor" d="m15.5 17.125l4.95-4.95q.275-.275.7-.275t.7.275t.275.7t-.275.7l-5.65 5.65q-.3.3-.7.3t-.7-.3l-2.85-2.85q-.275-.275-.275-.7t.275-.7t.7-.275t.7.275zM5 21q-.825 0-1.412-.587T3 19V5q0-.825.588-1.412T5 3h4.175q.275-.875 1.075-1.437T12 1q1 0 1.788.563T14.85 3H19q.825 0 1.413.588T21 5v4q0 .425-.288.713T20 10t-.712-.288T19 9V5h-2v2q0 .425-.288.713T16 8H8q-.425 0-.712-.288T7 7V5H5v14h5q.425 0 .713.288T11 20t-.288.713T10 21zm7-16q.425 0 .713-.288T13 4t-.288-.712T12 3t-.712.288T11 4t.288.713T12 5"/></svg>

After

Width:  |  Height:  |  Size: 611 B

View File

@ -24,7 +24,10 @@
} }
.header { .header {
@apply col-span-12 @apply col-span-12 flex gap-2 p-2.5;
.logo {
@apply text-primary text-2xl
}
} }
.sidebar { .sidebar {

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { object, string, type InferType } from 'yup' import { object, string, type InferType } from 'yup'
import { apiBase } from '~/helpers'; import { apiBase } from '~/helpers';
import type { ApiTypeBase, ApiTypeExternal } from '~/helpers'; import type { ApiTypeList, ApiTypeExternal } from '~/helpers';
import type { FormSubmitEvent } from '#ui/types' import type { FormSubmitEvent } from '#ui/types'
const props = defineProps(['elements', 'partner']) const props = defineProps(['elements', 'partner'])
@ -44,7 +44,7 @@ type Schema = InferType<typeof schema>
async function onSubmit(event: FormSubmitEvent<Schema>) { async function onSubmit(event: FormSubmitEvent<Schema>) {
const data = await $fetch(`${apiBase}/element/`, { method: 'POST', body: JSON.stringify(event.data) }) const data = await $fetch(`${apiBase}/element/`, { method: 'POST', body: JSON.stringify(event.data) })
const newElements = await $fetch<ApiTypeBase>(`${apiBase}/element?inventory_id=${route.params.inv_id}`, { headers }) const newElements = await $fetch<ApiTypeList>(`${apiBase}/element?inventory_id=${route.params.inv_id}`, { headers })
elements.value = newElements.results elements.value = newElements.results
} }
@ -153,3 +153,8 @@ onMounted(async () => {
</div> </div>
</div> </div>
</template> </template>
<style scoped>
label {
word-wrap: break-word;
}
</style>

View File

@ -1,13 +1,19 @@
const config = useRuntimeConfig() const config = useRuntimeConfig()
export const apiBase = config.public.apiBase export const apiBase = config.public.apiBase
export type ApiTypeBase = { export type ApiTypeList = {
count: number; count: number;
next?: any; next?: any;
previous?: any; previous?: any;
results: any[]; results: ApiTypeBase[]
} }
export type ApiTypeBase =
ApiPartner | ApiInventory | ApiElement;
export type ApiPartner = { id: number, external_id: number }
export type ApiInventory = { id: number, partner: number }
export type ApiElement = { id: number, external_id: string, element_id: number, photo: string, additional_text: string, inventory: number }
export type ApiTypeExternal = { export type ApiTypeExternal = {
'НаименованиеПолное': string; 'НаименованиеПолное': string;
Description: string; Description: string;

View File

@ -2,7 +2,7 @@
export default defineNuxtConfig({ export default defineNuxtConfig({
ssr: false, ssr: false,
devtools: { enabled: true }, devtools: { enabled: true },
modules: ["@nuxt/ui"], modules: ["@nuxt/ui", "nuxt-svgo"],
runtimeConfig: { runtimeConfig: {
public: { public: {
apiBase: '', apiBase: '',

View File

@ -9,6 +9,7 @@
"dependencies": { "dependencies": {
"@nuxt/ui": "^2.16.0", "@nuxt/ui": "^2.16.0",
"nuxt": "^3.11.2", "nuxt": "^3.11.2",
"nuxt-svgo": "^4.0.1",
"vue": "^3.4.27", "vue": "^3.4.27",
"vue-router": "^4.3.2", "vue-router": "^4.3.2",
"yup": "^1.4.0" "yup": "^1.4.0"
@ -8413,6 +8414,33 @@
"@nuxt/kit": "^3.11.1" "@nuxt/kit": "^3.11.1"
} }
}, },
"node_modules/nuxt-svgo": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/nuxt-svgo/-/nuxt-svgo-4.0.1.tgz",
"integrity": "sha512-jN82aehGXMXMkapNnk15Vr712EXtPIfG8SX8O//m5Ls/QgD7bbIMkGRbfJKfoX6a4NZm0ojkwvv/hWex8aVY/A==",
"dependencies": {
"@nuxt/kit": "^3.4.0",
"mini-svg-data-uri": "^1.4.4",
"svgo": "^3.0.2"
},
"peerDependencies": {
"svgo-loader": "^4.0.0",
"vue": ">=3.2.13",
"vue-loader": "^17.0.0",
"vue-svg-loader": "0.17.0-beta.2"
},
"peerDependenciesMeta": {
"svgo-loader": {
"optional": true
},
"vue-loader": {
"optional": true
},
"vue-svg-loader": {
"optional": true
}
}
},
"node_modules/nypm": { "node_modules/nypm": {
"version": "0.3.8", "version": "0.3.8",
"resolved": "https://registry.npmjs.org/nypm/-/nypm-0.3.8.tgz", "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.3.8.tgz",

View File

@ -12,6 +12,7 @@
"dependencies": { "dependencies": {
"@nuxt/ui": "^2.16.0", "@nuxt/ui": "^2.16.0",
"nuxt": "^3.11.2", "nuxt": "^3.11.2",
"nuxt-svgo": "^4.0.1",
"vue": "^3.4.27", "vue": "^3.4.27",
"vue-router": "^4.3.2", "vue-router": "^4.3.2",
"yup": "^1.4.0" "yup": "^1.4.0"

View File

@ -1,11 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { apiBase } from '~/helpers'; import { apiBase } from '~/helpers';
import type { ApiTypeBase } from '~/helpers'; import type { ApiTypeList } from '~/helpers';
const headers = new Headers(); const headers = new Headers();
headers.append("Content-Type", "application/json"); headers.append("Content-Type", "application/json");
const { data } = await useFetch<ApiTypeBase>(`${apiBase}/partner/`, { headers }) const { data } = await useFetch<ApiTypeList>(`${apiBase}/partner/`, { headers })
</script> </script>
<template> <template>
<div class="mb-4"> <div class="mb-4">

View File

@ -1,14 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { apiBase } from '~/helpers'; import { apiBase } from '~/helpers';
import type { ApiTypeBase } from '~/helpers'; import type { ApiPartner, ApiTypeList } from '~/helpers';
const headers = new Headers(); const headers = new Headers();
headers.append("Content-Type", "application/json"); headers.append("Content-Type", "application/json");
const route = useRoute() const route = useRoute()
const { data: partner } = await useFetch<ApiTypeBase>(`${apiBase}/partner/${route.params.org_id}`, { headers }) const { data: partner } = await useFetch<ApiPartner>(`${apiBase}/partner/${route.params.org_id}`, { headers })
const { data: elements } = await useFetch<ApiTypeBase>(`${apiBase}/element?inventory_id=${route.params.inv_id}`, { headers }) const { data: elements } = await useFetch<ApiTypeList>(`${apiBase}/element?inventory_id=${route.params.inv_id}`, { headers })
</script> </script>
<template> <template>
<Edit :elements="elements?.results" :inventory="route.params.org_id" :partner="partner?.external_id"/> <Edit :elements="elements?.results" :inventory="route.params.org_id" :partner="partner?.external_id"/>

View File

@ -1,13 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { apiBase } from '~/helpers'; import { apiBase } from '~/helpers';
import type { ApiTypeBase } from '~/helpers'; import type { ApiTypeList } from '~/helpers';
const headers = new Headers(); const headers = new Headers();
headers.append("Content-Type", "application/json"); headers.append("Content-Type", "application/json");
const route = useRoute() const route = useRoute()
const { data } = await useFetch<ApiTypeBase>(`${apiBase}/element?inventory_id=${route.params.inv_id}`, { headers }) const { data } = await useFetch<ApiTypeList>(`${apiBase}/element?inventory_id=${route.params.inv_id}`, { headers })
</script> </script>
<template> <template>
<div class="mb-4"> <div class="mb-4">

View File

@ -1,13 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { apiBase } from '~/helpers'; import { apiBase } from '~/helpers';
import type { ApiTypeBase } from '~/helpers'; import type { ApiTypeList } from '~/helpers';
const headers = new Headers(); const headers = new Headers();
headers.append("Content-Type", "application/json"); headers.append("Content-Type", "application/json");
const route = useRoute() const route = useRoute()
const { data } = await useFetch<ApiTypeBase>(`${apiBase}/inventory?partner_id=${route.params.org_id}`, { headers }) const { data } = await useFetch<ApiTypeList>(`${apiBase}/inventory?partner_id=${route.params.org_id}`, { headers })
</script> </script>
<template> <template>
<UTable :rows="data?.results"> <UTable :rows="data?.results">