base add
This commit is contained in:
parent
dd32cf6432
commit
fa49de322d
|
@ -10,7 +10,7 @@ class PartnerSerializer(serializers.ModelSerializer):
|
||||||
class InventorySerializer(serializers.ModelSerializer):
|
class InventorySerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = InventoryItem
|
model = InventoryItem
|
||||||
fields = ["id"]
|
fields = ["id", "partner"]
|
||||||
|
|
||||||
class ElementSerializer(serializers.ModelSerializer):
|
class ElementSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -106,7 +106,7 @@ 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"]).exist()
|
# and InventoryItem.objects.filter(id=data["inventory"]).exists()
|
||||||
):
|
):
|
||||||
inventory_object = InventoryItem.objects.get(id=data["inventory"])
|
inventory_object = InventoryItem.objects.get(id=data["inventory"])
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { object, string, type InferType } from 'yup'
|
||||||
|
import { apiBase } from '~/helpers';
|
||||||
|
import type { ApiTypeBase, ApiTypeExternal } from '~/helpers';
|
||||||
|
import type { FormSubmitEvent } from '#ui/types'
|
||||||
|
|
||||||
|
const props = defineProps(['elements', 'partner'])
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const headers = new Headers();
|
||||||
|
headers.append("Content-Type", "application/json");
|
||||||
|
|
||||||
|
type ExternalDataType = {
|
||||||
|
partner?: ApiTypeExternal[],
|
||||||
|
categories?: ApiTypeExternal[][],
|
||||||
|
element?: ApiTypeExternal[],
|
||||||
|
}
|
||||||
|
type StateDataType = {
|
||||||
|
partner?: string
|
||||||
|
categories?: string[]
|
||||||
|
inventory?: string
|
||||||
|
element?: string
|
||||||
|
element_id?: string
|
||||||
|
}
|
||||||
|
const loading = ref(false)
|
||||||
|
const state = reactive<StateDataType>({
|
||||||
|
partner: undefined,
|
||||||
|
categories: [],
|
||||||
|
inventory: route.params.inv_id as string || undefined,
|
||||||
|
element: undefined,
|
||||||
|
element_id: undefined
|
||||||
|
})
|
||||||
|
const external_data = reactive<ExternalDataType>({
|
||||||
|
partner: [],
|
||||||
|
categories: [],
|
||||||
|
element: [],
|
||||||
|
})
|
||||||
|
const elements = ref(props.elements)
|
||||||
|
const schema = object({
|
||||||
|
element: string().required('Required'),
|
||||||
|
element_id: string().required('Required')
|
||||||
|
})
|
||||||
|
type Schema = InferType<typeof schema>
|
||||||
|
|
||||||
|
async function onSubmit(event: FormSubmitEvent<Schema>) {
|
||||||
|
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 })
|
||||||
|
elements.value = newElements.results
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchInExternal = (q: string) => {
|
||||||
|
if (!q.length) {
|
||||||
|
return external_data.partner?.splice(0, 10)
|
||||||
|
}
|
||||||
|
return external_data.partner?.filter(el => {
|
||||||
|
return el.Description.toLowerCase().indexOf(q.toLowerCase()) !== -1
|
||||||
|
}).slice(0, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadPartners = async () => {
|
||||||
|
loading.value = true
|
||||||
|
const data = await $fetch<ApiTypeExternal[]>(`${apiBase}/partner/external/`)
|
||||||
|
if (data) {
|
||||||
|
external_data.partner = data
|
||||||
|
if (props.partner) {
|
||||||
|
state.partner = props.partner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
const loadCategories = async () => {
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
const lastCat = state.categories?.at(-1) || ''
|
||||||
|
const data = await $fetch<ApiTypeExternal[]>(`${apiBase}/element/external_categories/${lastCat}`)
|
||||||
|
if (data.length) {
|
||||||
|
external_data.categories?.push(data)
|
||||||
|
} else {
|
||||||
|
await loadElements()
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
const loadElements = async () => {
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
const lastCat = state.categories?.at(-1) || ''
|
||||||
|
const data = await $fetch<ApiTypeExternal[]>(`${apiBase}/element/external/${lastCat}`)
|
||||||
|
if (data) {
|
||||||
|
external_data.element = data
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
const loadDeepCategories = async (i: number) => {
|
||||||
|
if ((i + 1) <= (state.categories as string[]).length) {
|
||||||
|
state.categories = state.categories?.slice(0, i + 1)
|
||||||
|
external_data.categories = external_data.categories?.slice(0, i + 1)
|
||||||
|
|
||||||
|
state.element = undefined
|
||||||
|
external_data.element = []
|
||||||
|
}
|
||||||
|
|
||||||
|
loadCategories()
|
||||||
|
}
|
||||||
|
onMounted(async () => {
|
||||||
|
await loadPartners()
|
||||||
|
await loadCategories()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="grid grid-cols-10 gap-4">
|
||||||
|
<div class="col-span-3">
|
||||||
|
<UForm :state="state" class="flex flex-col gap-4" @submit="onSubmit">
|
||||||
|
<UFormGroup label="Выбрать организацию" name="organization">
|
||||||
|
<USelectMenu v-model="state.partner" :options="external_data.partner" value-attribute="Ref_Key"
|
||||||
|
option-attribute="Description" :searchable="searchInExternal"
|
||||||
|
searchable-placeholder="Выберите организацию из списка контрагентов" :loading="loading"
|
||||||
|
:disabled="!!props.partner" />
|
||||||
|
</UFormGroup>
|
||||||
|
<UFormGroup label="Добавить элемент инвентаризации" v-if="state.partner">
|
||||||
|
<template v-for="(item, i) in external_data.categories">
|
||||||
|
<USelectMenu v-model="(state.categories as string[])[i]" :options="item"
|
||||||
|
value-attribute="Ref_Key" option-attribute="Description" :searchable="true"
|
||||||
|
:loading="loading" :placeholder="`Категории (${item.length})`"
|
||||||
|
@change="loadDeepCategories(i)" />
|
||||||
|
</template>
|
||||||
|
<USelectMenu v-if="external_data.element?.length" v-model="state.element"
|
||||||
|
:options="external_data.element" value-attribute="Ref_Key" option-attribute="Description"
|
||||||
|
:searchable="true" :loading="loading"
|
||||||
|
:placeholder="`Элементы (${external_data.element.length})`" />
|
||||||
|
</UFormGroup>
|
||||||
|
<UFormGroup v-if="state.element"
|
||||||
|
:label="`Данные об элементе «${external_data.element?.find(el => el['Ref_Key'] === state.element)?.Description}»`">
|
||||||
|
<UInput placeholder="ID" v-model="state.element_id" />
|
||||||
|
</UFormGroup>
|
||||||
|
|
||||||
|
<UButton type="submit" :disabled="!state.element_id">
|
||||||
|
Сохранить
|
||||||
|
</UButton>
|
||||||
|
</UForm>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-7">
|
||||||
|
<h2>{{ external_data.partner?.find(el => el["Ref_Key"] == state.partner)?.Description }}</h2>
|
||||||
|
<dl v-if="elements?.length">
|
||||||
|
<template v-for="item in elements">
|
||||||
|
<dt>
|
||||||
|
{{ item.external_id }}
|
||||||
|
</dt>
|
||||||
|
<dt>
|
||||||
|
{{ item.element_id }}
|
||||||
|
</dt>
|
||||||
|
</template>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -9,7 +9,7 @@ const { data } = await useFetch<ApiTypeBase>(`${apiBase}/partner/`, { headers })
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<UButton icon="i-heroicons-plus" to="organization/new">Новая инвентаризация</UButton>
|
<UButton icon="i-heroicons-plus" to="/organization/new">Новая инвентаризация</UButton>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<UTable :rows="data?.results">
|
<UTable :rows="data?.results">
|
||||||
|
|
|
@ -1,135 +1,3 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import { object, string, type InferType } from 'yup'
|
|
||||||
import { apiBase } from '~/helpers';
|
|
||||||
import type { ApiTypeExternal } from '~/helpers';
|
|
||||||
import type { FormSubmitEvent } from '#ui/types'
|
|
||||||
|
|
||||||
type ExternalDataType = {
|
|
||||||
partner?: ApiTypeExternal[],
|
|
||||||
categories?: ApiTypeExternal[][],
|
|
||||||
element?: ApiTypeExternal[],
|
|
||||||
}
|
|
||||||
type StateDataType = {
|
|
||||||
partner?: string
|
|
||||||
categories?: string[]
|
|
||||||
inventory?: string
|
|
||||||
element?: string
|
|
||||||
element_id?: string
|
|
||||||
}
|
|
||||||
const loading = ref(false)
|
|
||||||
const state = reactive<StateDataType>({
|
|
||||||
partner: undefined,
|
|
||||||
categories: [],
|
|
||||||
inventory: undefined,
|
|
||||||
element: undefined,
|
|
||||||
element_id: undefined
|
|
||||||
})
|
|
||||||
const external_data = reactive<ExternalDataType>({
|
|
||||||
partner: [],
|
|
||||||
categories: [],
|
|
||||||
element: [],
|
|
||||||
})
|
|
||||||
const schema = object({
|
|
||||||
element: string().required('Required'),
|
|
||||||
element_id: string().required('Required')
|
|
||||||
})
|
|
||||||
type Schema = InferType<typeof schema>
|
|
||||||
|
|
||||||
async function onSubmit(event: FormSubmitEvent<Schema>) {
|
|
||||||
const data = await $fetch(`${apiBase}/element/`, { method: 'POST', body: JSON.stringify(event.data) })
|
|
||||||
if(data.partner) {
|
|
||||||
// navigateTo(`/organization/${data.partner.id}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const searchInExternal = (q: string) => {
|
|
||||||
if (!q.length) {
|
|
||||||
return external_data.partner?.splice(0, 10)
|
|
||||||
}
|
|
||||||
return external_data.partner?.filter(el => {
|
|
||||||
return el.Description.toLowerCase().indexOf(q.toLowerCase()) !== -1
|
|
||||||
}).slice(0, 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadPartners = async () => {
|
|
||||||
loading.value = true
|
|
||||||
const data = await $fetch<ApiTypeExternal[]>(`${apiBase}/partner/external/`)
|
|
||||||
if (data) {
|
|
||||||
external_data.partner = data
|
|
||||||
}
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
const loadCategories = async () => {
|
|
||||||
loading.value = true
|
|
||||||
|
|
||||||
const lastCat = state.categories?.at(-1) || ''
|
|
||||||
const data = await $fetch<ApiTypeExternal[]>(`${apiBase}/element/external_categories/${lastCat}`)
|
|
||||||
if (data.length) {
|
|
||||||
external_data.categories?.push(data)
|
|
||||||
} else {
|
|
||||||
await loadElements()
|
|
||||||
}
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
const loadElements = async () => {
|
|
||||||
loading.value = true
|
|
||||||
|
|
||||||
const lastCat = state.categories?.at(-1) || ''
|
|
||||||
const data = await $fetch<ApiTypeExternal[]>(`${apiBase}/element/external/${lastCat}`)
|
|
||||||
if (data) {
|
|
||||||
external_data.element = data
|
|
||||||
}
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
const loadDeepCategories = async (i: number) => {
|
|
||||||
if ((i + 1) <= (state.categories as string[]).length) {
|
|
||||||
state.categories = state.categories?.slice(0, i + 1)
|
|
||||||
external_data.categories = external_data.categories?.slice(0, i + 1)
|
|
||||||
|
|
||||||
state.element = undefined
|
|
||||||
external_data.element = []
|
|
||||||
}
|
|
||||||
|
|
||||||
loadCategories()
|
|
||||||
}
|
|
||||||
onMounted(async () => {
|
|
||||||
await loadPartners()
|
|
||||||
await loadCategories()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
<template>
|
<template>
|
||||||
<div class="grid grid-cols-10 gap-4">
|
<Edit />
|
||||||
<div class="col-span-3">
|
|
||||||
<UForm :state="state" class="flex flex-col gap-4" @submit="onSubmit">
|
|
||||||
<UFormGroup label="Выбрать организацию" name="organization">
|
|
||||||
<USelectMenu v-model="state.partner" :options="external_data.partner" value-attribute="Ref_Key"
|
|
||||||
option-attribute="Description" :searchable="searchInExternal"
|
|
||||||
searchable-placeholder="Выберите организацию из списка контрагентов" :loading="loading" />
|
|
||||||
</UFormGroup>
|
|
||||||
<UFormGroup label="Добавить элемент инвентаризации" v-if="state.partner">
|
|
||||||
<template v-for="(item, i) in external_data.categories">
|
|
||||||
<USelectMenu v-model="(state.categories as string[])[i]" :options="item"
|
|
||||||
value-attribute="Ref_Key" option-attribute="Description" :searchable="true"
|
|
||||||
:loading="loading" :placeholder="`Категории (${item.length})`"
|
|
||||||
@change="loadDeepCategories(i)" />
|
|
||||||
</template>
|
|
||||||
<USelectMenu v-if="external_data.element?.length" v-model="state.element"
|
|
||||||
:options="external_data.element" value-attribute="Ref_Key" option-attribute="Description"
|
|
||||||
:searchable="true" :loading="loading"
|
|
||||||
:placeholder="`Элементы (${external_data.element.length})`" />
|
|
||||||
</UFormGroup>
|
|
||||||
<UFormGroup v-if="state.element"
|
|
||||||
:label="`Данные об элементе «${external_data.element?.find(el => el['Ref_Key'] === state.element)?.Description}»`">
|
|
||||||
<UInput placeholder="ID" v-model="state.element_id" />
|
|
||||||
</UFormGroup>
|
|
||||||
|
|
||||||
<UButton type="submit" :disabled="!state.element_id">
|
|
||||||
Сохранить
|
|
||||||
</UButton>
|
|
||||||
</UForm>
|
|
||||||
</div>
|
|
||||||
<div class="col-span-7">
|
|
||||||
<h2>{{ external_data.partner?.find(el => el["Ref_Key"] == state.partner)?.Description }}</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
|
@ -1,15 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import { apiBase } from '~/helpers';
|
|
||||||
import type { ApiTypeBase } from '~/helpers';
|
|
||||||
|
|
||||||
const headers = new Headers();
|
|
||||||
headers.append("Content-Type", "application/json");
|
|
||||||
|
|
||||||
const route = useRoute()
|
|
||||||
|
|
||||||
const { data } = await useFetch<ApiTypeBase>(`${apiBase}/element?inventory_id=${route.params.id}`, { headers })
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<UTable :rows="data?.results">
|
|
||||||
</UTable>
|
|
||||||
</template>
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { apiBase } from '~/helpers';
|
||||||
|
import type { ApiTypeBase } from '~/helpers';
|
||||||
|
|
||||||
|
const headers = new Headers();
|
||||||
|
headers.append("Content-Type", "application/json");
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const { data: partner } = await useFetch<ApiTypeBase>(`${apiBase}/partner/${route.params.org_id}`, { headers })
|
||||||
|
const { data: elements } = await useFetch<ApiTypeBase>(`${apiBase}/element?inventory_id=${route.params.inv_id}`, { headers })
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<Edit :elements="elements?.results" :inventory="route.params.org_id" :partner="partner?.external_id"/>
|
||||||
|
</template>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { apiBase } from '~/helpers';
|
||||||
|
import type { ApiTypeBase } from '~/helpers';
|
||||||
|
|
||||||
|
const headers = new Headers();
|
||||||
|
headers.append("Content-Type", "application/json");
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const { data } = await useFetch<ApiTypeBase>(`${apiBase}/element?inventory_id=${route.params.inv_id}`, { headers })
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="mb-4">
|
||||||
|
<UButton icon="i-heroicons-plus" :to="`/organization/p_${route.params.org_id}/i_${route.params.inv_id}/edit`">
|
||||||
|
Добавить элемент</UButton>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<UTable :rows="data?.results" />
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -7,12 +7,12 @@ headers.append("Content-Type", "application/json");
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
const { data } = await useFetch<ApiTypeBase>(`${apiBase}/inventory?partner_id=${route.params.id}`, { headers })
|
const { data } = await useFetch<ApiTypeBase>(`${apiBase}/inventory?partner_id=${route.params.org_id}`, { headers })
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<UTable :rows="data?.results">
|
<UTable :rows="data?.results">
|
||||||
<template #id-data="{ row }">
|
<template #id-data="{ row }">
|
||||||
<NuxtLink :to="`/organization/p_${route.params.id}/i_${row.id}`">
|
<NuxtLink :to="`/organization/p_${route.params.org_id}/i_${row.id}`">
|
||||||
{{ row.id }}
|
{{ row.id }}
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</template>
|
</template>
|
Loading…
Reference in New Issue