merge ui
This commit is contained in:
94
frontend/src/table/DialogWindow.vue
Normal file
94
frontend/src/table/DialogWindow.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<script setup lang="ts" generic="T extends IEntity">
|
||||
import { Button, DatePicker, Dialog, InputNumber, InputText, MultiSelect, Select, Textarea, ToggleSwitch } from 'primevue';
|
||||
import type { IEntity } from '../types/entity.type';
|
||||
import type { Scheme } from '../types/scheme.type';
|
||||
import type { IService } from '../types/service.type';
|
||||
import { manyStructsView } from '../utils/structs/structs-view.util';
|
||||
import { type UnwrapRef } from 'vue';
|
||||
|
||||
const showCreate = defineModel<boolean>('show')
|
||||
const createItem = defineModel<T>('item')
|
||||
|
||||
const items = defineModel<UnwrapRef<T[]>>('items')
|
||||
|
||||
const props = defineProps<{
|
||||
scheme: Scheme<T>,
|
||||
getDefaults: () => Partial<T>,
|
||||
service: IService<T>,
|
||||
updateMode?: boolean
|
||||
}>()
|
||||
|
||||
type Key = keyof T
|
||||
const keys = Object.keys(props.scheme) as Key[]
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'onSave', data: any): void
|
||||
(e: 'onSaveUpdate', data: any): void
|
||||
(e: 'onSaveCreate', data: any): void
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-model:visible="showCreate">
|
||||
<div class="flex flex-col justify-center gap-5">
|
||||
<div v-for="key in keys" v-show="!props.scheme[key].hidden && !props.scheme[key].readonly"
|
||||
class="flex items-center gap-5">
|
||||
<h1 class="w-[200px]">{{ props.scheme[key].russian }}</h1>
|
||||
<div>
|
||||
<div v-if="props.scheme[key]?.customWindow?.[props.updateMode ? 'update' : 'create']">
|
||||
<slot :name="<string>key + (props.updateMode ? 'Update' : 'Create')"></slot>
|
||||
</div>
|
||||
<div v-else-if="props.scheme[key]?.customWindow?.common">
|
||||
<slot :name="<string>key"></slot>
|
||||
</div>
|
||||
<InputNumber class="w-[300px]" v-model:model-value="<number>createItem![key]"
|
||||
v-else-if="props.scheme[key]?.type?.primitive === 'number'" />
|
||||
<InputText class="w-[300px]" v-model:model-value="<string>createItem![key]"
|
||||
v-else-if="props.scheme[key].type?.primitive === 'string'" />
|
||||
<DatePicker class="w-[300px]" v-model:model-value="<Date>createItem![key]"
|
||||
v-else-if="props.scheme[key].type?.primitive === 'date'" />
|
||||
<Textarea class="w-[300px]" v-model="<string>createItem![key]"
|
||||
v-else-if="props.scheme[key].type?.primitive === 'multiple'" />
|
||||
<ToggleSwitch class="w-[300px]" v-model:model-value="<boolean>createItem![key]"
|
||||
v-else-if="props.scheme[key].type?.primitive === 'boolean'" />
|
||||
<Select v-else-if="props.scheme[key].type?.nested?.values && !props.scheme[key].type?.many"
|
||||
v-model:model-value="createItem![key]" :options="props.scheme[key].type.nested.values"
|
||||
:placeholder="`Выберите ${props.scheme[key].russian}`" class="w-[300px]">
|
||||
<template #option="{ option }">
|
||||
{{ manyStructsView(option, props.scheme[key].type.nested.field) }}
|
||||
</template>
|
||||
<template #value="{ value }">
|
||||
{{ manyStructsView(value, props.scheme[key].type.nested.field) }}
|
||||
</template>
|
||||
</Select>
|
||||
<MultiSelect v-else-if="props.scheme[key].type?.many" v-model:model-value="createItem![key]"
|
||||
:options="props.scheme[key].type?.nested?.values"
|
||||
class="w-[300px] h-11"
|
||||
:placeholder="`Выберите ${props.scheme[key].russian}`">
|
||||
<template #option="{ option }">
|
||||
{{ manyStructsView(option, props.scheme[key]?.type?.nested?.field) }}
|
||||
</template>
|
||||
<template #value="{ value }">
|
||||
{{ manyStructsView(value, props.scheme[key]?.type?.nested?.field) }}
|
||||
</template>
|
||||
</MultiSelect>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<Button severity="success" @click="async () => {
|
||||
if (props.updateMode) {
|
||||
props.service.update(createItem as T)
|
||||
emits('onSaveUpdate', createItem as T)
|
||||
emits('onSave', createItem as T)
|
||||
} else {
|
||||
props.service.create(createItem as T)
|
||||
emits('onSaveCreate', createItem as T)
|
||||
emits('onSave', createItem as T)
|
||||
}
|
||||
items = await service.readAll() as UnwrapRef<T[]>
|
||||
showCreate = false
|
||||
}">Сохранить</Button>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
155
frontend/src/table/Table.vue
Normal file
155
frontend/src/table/Table.vue
Normal file
@@ -0,0 +1,155 @@
|
||||
<script setup lang="ts" generic="T extends IEntity">
|
||||
import { onMounted, ref, watch, type UnwrapRef } from "vue";
|
||||
import type { TableProps } from "../types/table-props.type";
|
||||
import { DataTable, Column, Button } from "primevue";
|
||||
import { manyStructsView } from "../utils/structs/structs-view.util";
|
||||
import type { TableEmits } from "../types/table-emits.type";
|
||||
import FloatingButton from "../components/buttons/FloatingButton.vue";
|
||||
import type { IEntity } from "../types/entity.type";
|
||||
import DialogWindow from "./DialogWindow.vue";
|
||||
|
||||
const props = defineProps<TableProps<T>>();
|
||||
|
||||
const items = ref<T[]>([]);
|
||||
|
||||
onMounted(async () => {
|
||||
items.value = await props.service.readAll();
|
||||
});
|
||||
|
||||
type Key = keyof T;
|
||||
const keys = Object.keys(props.scheme) as Key[];
|
||||
const emits = defineEmits<TableEmits>();
|
||||
|
||||
const showCreate = ref(false);
|
||||
const createItem = ref<null | T>(null);
|
||||
|
||||
const showUpdate = ref(false);
|
||||
const updateItem = ref<null | T>(null);
|
||||
|
||||
watch(showUpdate, (value) => {
|
||||
if (!value) {
|
||||
updateItem.value = null;
|
||||
}
|
||||
});
|
||||
|
||||
watch(updateItem, (value) => {
|
||||
if (value) {
|
||||
showUpdate.value = true;
|
||||
} else {
|
||||
showUpdate.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
watch(showCreate, (value) => {
|
||||
if (value) {
|
||||
createItem.value = props.getDefaults();
|
||||
} else {
|
||||
createItem.value = null;
|
||||
}
|
||||
});
|
||||
|
||||
watch(createItem, (value) => {
|
||||
if (value) {
|
||||
showCreate.value = true;
|
||||
} else {
|
||||
showCreate.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
const handleFloatingButtonClick = () => {
|
||||
emits('onCreateOpen')
|
||||
emits('onOpen')
|
||||
showCreate.value = true;
|
||||
};
|
||||
const slots = defineSlots();
|
||||
|
||||
const createSlotName = (key: any) => key + "Create";
|
||||
const updateSlotName = (key: any) => key + "Update";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogWindow
|
||||
:scheme="props.scheme"
|
||||
:service="props.service"
|
||||
:get-defaults="props.getDefaults"
|
||||
v-model:item="<T>createItem"
|
||||
v-model:show="showCreate"
|
||||
v-model:items="items"
|
||||
@on-save="data => emits('onSave', data)"
|
||||
@on-save-create="data => emits('onSaveCreate', data)"
|
||||
>
|
||||
<template v-for="key in keys" #[key]>
|
||||
<slot :name="<string>key"></slot>
|
||||
</template>
|
||||
<template v-for="key in keys" #[createSlotName(key)]>
|
||||
<slot :name="createSlotName(key)"></slot>
|
||||
</template>
|
||||
</DialogWindow>
|
||||
<DialogWindow
|
||||
:scheme="props.scheme"
|
||||
update-mode
|
||||
:service="props.service"
|
||||
:get-defaults="props.getDefaults"
|
||||
v-model:item="<T>updateItem"
|
||||
v-model:show="showUpdate"
|
||||
v-model:items="items"
|
||||
@on-save="data => emits('onSave', data)"
|
||||
@on-save-update="data => emits('onSaveUpdate', data)"
|
||||
>
|
||||
<template v-for="key in keys" #[key]>
|
||||
<slot :name="<string>key"></slot>
|
||||
</template>
|
||||
<template v-for="key in keys" #[updateSlotName(key)]>
|
||||
<slot :name="updateSlotName(key)"></slot>
|
||||
</template>
|
||||
</DialogWindow>
|
||||
<div>
|
||||
<DataTable :value="<[]>items">
|
||||
<template #header v-if="props.name">
|
||||
<p>{{ props.name }}</p>
|
||||
</template>
|
||||
<template v-for="key in keys">
|
||||
<Column
|
||||
:header="props.scheme[key]?.russian"
|
||||
v-if="!props.scheme[key].hidden"
|
||||
>
|
||||
<template #body="{ data }">
|
||||
<p>
|
||||
{{
|
||||
manyStructsView(
|
||||
data[key],
|
||||
props.scheme[key]?.type?.nested?.field,
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
</template>
|
||||
</Column>
|
||||
</template>
|
||||
<Column header="Действия">
|
||||
<template #body="{ data }">
|
||||
<div class="flex gap-2">
|
||||
<Button
|
||||
severity="secondary"
|
||||
icon="pi pi-pencil"
|
||||
@click="() => {
|
||||
emits('onUpdateOpen')
|
||||
emits('onOpen')
|
||||
updateItem = data
|
||||
}"
|
||||
></Button>
|
||||
<Button
|
||||
severity="danger"
|
||||
icon="pi pi-trash"
|
||||
@click="async () => {
|
||||
emits('onDelete', data)
|
||||
await props.service.delete(data.Id)
|
||||
items = await props.service.readAll() as UnwrapRef<T[]>
|
||||
}"
|
||||
></Button>
|
||||
</div>
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
<FloatingButton @click="handleFloatingButtonClick" />
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user