201 lines
8.0 KiB
Vue
201 lines
8.0 KiB
Vue
<script setup lang="ts">
|
||
import { apiBase } from '~/helpers';
|
||
import type { ApiTypeList, ApiTypeExternal, ApiElementSave } from '~/helpers';
|
||
import type { FormError, 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
|
||
element_additional_data?: 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,
|
||
element_additional_data: undefined
|
||
})
|
||
const external_data = reactive<ExternalDataType>({
|
||
partner: [],
|
||
categories: [],
|
||
element: [],
|
||
})
|
||
const show_error = ref()
|
||
|
||
const elements = ref(props.elements)
|
||
const validate = (state: any): FormError[] => {
|
||
const errors = []
|
||
const txt = 'Это поле обязательно'
|
||
if (!state.partner) errors.push({ path: 'partner', message: txt })
|
||
if (!external_data || !external_data.partner || !external_data.partner.find(el => el.Ref_Key == state.partner)) {
|
||
errors.push({ path: 'partner', message: txt })
|
||
}
|
||
if (!state.element_id) errors.push({ path: 'element_id', message: txt })
|
||
// if (!state.element_additional_data) errors.push({ path: 'element_additional_data', message: txt })
|
||
return errors
|
||
}
|
||
|
||
async function onSubmit(event: FormSubmitEvent<any>) {
|
||
show_error.value = undefined
|
||
const prepader_data = event.data
|
||
if (!external_data || !external_data.partner) {
|
||
return false
|
||
}
|
||
prepader_data.partner_name = external_data.partner.find(el => el.Ref_Key == state.partner)?.Description
|
||
|
||
const data = await $fetch<ApiElementSave>(`${apiBase}/element/`, {
|
||
method: 'POST', body: JSON.stringify(prepader_data), onResponseError: (error) => {
|
||
if (error.response.status == 500) {
|
||
show_error.value = Object.entries(error.response._data).map(el => `${el[0]}: ${el[1]}`).join('\n')
|
||
}
|
||
}
|
||
})
|
||
const inv_id = route.params.inv_id || data.inventory?.id
|
||
if (!route.params.inv_id) {
|
||
navigateTo(`/organization/p_${data.partner.id}/i_${data.inventory.id}`)
|
||
} else {
|
||
const newElements = await $fetch<ApiTypeList>(`${apiBase}/element?inventory_id=${inv_id}`, { headers })
|
||
elements.value = newElements.results
|
||
external_data.element = []
|
||
external_data.categories = []
|
||
state.categories = []
|
||
state.element = undefined
|
||
state.element_id = undefined
|
||
state.element_additional_data = undefined
|
||
}
|
||
}
|
||
|
||
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-7">
|
||
<UForm :state="state" :validate="validate" class="flex flex-col gap-4" @submit="onSubmit">
|
||
<UFormGroup label="Выбрать организацию" name="partner">
|
||
<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" :help="!external_data.element?.length ? `Последовательно
|
||
выбирайте категорию. Если все выбрали, а элементов нет -
|
||
значит в этой категории нет элементов`: ''">
|
||
<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>
|
||
<div v-if="state.element">
|
||
<h4>Данные об элементе «{{ external_data.element?.find(el => el['Ref_Key'] ===
|
||
state.element)?.Description }}»</h4>
|
||
<UFormGroup label="ID" name="element_id">
|
||
<UInput placeholder="ID" v-model="state.element_id" />
|
||
</UFormGroup>
|
||
<UFormGroup label="Дополнительные сведения" name="element_additional_data">
|
||
<UTextarea placeholder="Дополнительные сведения" v-model="state.element_additional_data" />
|
||
</UFormGroup>
|
||
</div>
|
||
|
||
<UButton type="submit" :disabled="!state.element_id">
|
||
Сохранить
|
||
</UButton>
|
||
</UForm>
|
||
</div>
|
||
<div class="col-span-3 flex flex-col gap-4">
|
||
<h2>{{ external_data.partner?.find(el => el["Ref_Key"] == state.partner)?.Description }}</h2>
|
||
<UAlert v-if="show_error" title="Server error" :description="show_error" color="primary" />
|
||
<dl v-if="elements?.length">
|
||
<template v-for="item in elements">
|
||
<dt>
|
||
<Element :id="item.external_id" />
|
||
</dt>
|
||
<dd>{{ item.element_id }}</dd>
|
||
<dd>{{ item.additional_text }}</dd>
|
||
</template>
|
||
</dl>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<style scoped>
|
||
label {
|
||
word-wrap: break-word;
|
||
}
|
||
</style> |