feat: import prodect from file
Some checks failed
Spell Check / Spell Check with Typos (push) Failing after 6s

This commit is contained in:
Thanaphon Frappet 2025-04-22 13:58:26 +07:00
parent 74291c0552
commit 8d8ad40de1
3 changed files with 70 additions and 6 deletions

View file

@ -1,8 +1,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue';
import MainButton from './MainButton.vue'; import MainButton from './MainButton.vue';
defineEmits<{ const emit = defineEmits<{
(e: 'click', v: MouseEvent): void; (e: 'click', v: MouseEvent): void;
(e: 'fileSelected', v: File[]): void;
}>(); }>();
defineProps<{ defineProps<{
iconOnly?: boolean; iconOnly?: boolean;
@ -10,15 +12,29 @@ defineProps<{
outlined?: boolean; outlined?: boolean;
disabled?: boolean; disabled?: boolean;
dark?: boolean; dark?: boolean;
importFile?: boolean;
label?: string; label?: string;
icon?: string; icon?: string;
}>(); }>();
const inputRef = ref<HTMLInputElement | null>(null);
function triggerFileInput() {
inputRef.value?.click();
}
function handleFileChange(event: Event) {
const files = (event.target as HTMLInputElement).files;
if (files && files.length > 0) {
emit('fileSelected', Array.from(files));
}
}
</script> </script>
<template> <template>
<MainButton <MainButton
@click="(e) => $emit('click', e)" @click="(e) => (importFile ? triggerFileInput() : $emit('click', e))"
v-bind="{ ...$props, ...$attrs }" v-bind="{ ...$props, ...$attrs }"
:icon="icon || 'mdi-import'" :icon="icon || 'mdi-import'"
color="var(--info-bg)" color="var(--info-bg)"
@ -26,4 +42,13 @@ defineProps<{
> >
{{ label || $t('general.import') }} {{ label || $t('general.import') }}
</MainButton> </MainButton>
<input
ref="inputRef"
type="file"
@change="(e) => handleFileChange(e)"
hidden
accept=".xls, .xlsx , .csv"
multiple
/>
</template> </template>

View file

@ -34,6 +34,7 @@ import {
UndoButton, UndoButton,
ToggleButton, ToggleButton,
PasteButton, PasteButton,
ImportButton,
} from 'components/button'; } from 'components/button';
import TableProduct from 'src/components/04_product-service/TableProduct.vue'; import TableProduct from 'src/components/04_product-service/TableProduct.vue';
import PaginationPageSize from 'src/components/PaginationPageSize.vue'; import PaginationPageSize from 'src/components/PaginationPageSize.vue';
@ -99,6 +100,8 @@ const {
createWork, createWork,
editWork, editWork,
deleteWork, deleteWork,
importProduct,
} = productServiceStore; } = productServiceStore;
const currentCopy = ref<{ const currentCopy = ref<{
@ -107,6 +110,7 @@ const currentCopy = ref<{
}>(); }>();
const { workNameItems } = storeToRefs(productServiceStore); const { workNameItems } = storeToRefs(productServiceStore);
const allStat = ref<{ mode: string; count: number }[]>([]); const allStat = ref<{ mode: string; count: number }[]>([]);
const stat = ref< const stat = ref<
{ {
icon: string; icon: string;
@ -2262,7 +2266,6 @@ watch(
}, },
]" ]"
></q-select> ></q-select>
<q-select <q-select
v-if="modeView === false" v-if="modeView === false"
id="select-field" id="select-field"
@ -2285,7 +2288,6 @@ watch(
multiple multiple
dense dense
/> />
<q-btn-toggle <q-btn-toggle
v-model="modeView" v-model="modeView"
id="btn-mode" id="btn-mode"
@ -2760,6 +2762,26 @@ watch(
</AdvanceSearch> </AdvanceSearch>
</template> </template>
</q-input> </q-input>
<div
class="flex q-mr-auto q-pl-sm"
v-if="productAndServiceTab === 'product'"
>
<input ref="fileImport" type="file" hidden />
<ImportButton
type="file"
import-file
icon-only
@file-selected="
(file) => {
importProduct(
currentIdGroup,
file,
async () => await fetchListOfProduct(),
);
}
"
/>
</div>
<div class="row col-md-6" style="white-space: nowrap"> <div class="row col-md-6" style="white-space: nowrap">
<q-select <q-select
@ -2785,7 +2807,6 @@ watch(
]" ]"
@update:model-value="fetchStatus()" @update:model-value="fetchStatus()"
></q-select> ></q-select>
<q-select <q-select
v-if="modeView === false" v-if="modeView === false"
:hide-dropdown-icon="$q.screen.lt.sm" :hide-dropdown-icon="$q.screen.lt.sm"
@ -2820,7 +2841,6 @@ watch(
multiple multiple
dense dense
/> />
<q-btn-toggle <q-btn-toggle
v-model="modeView" v-model="modeView"
id="btn-mode" id="btn-mode"

View file

@ -194,6 +194,23 @@ const useProductServiceStore = defineStore('api-product-service', () => {
return false; return false;
} }
async function importProduct(
productGroupId: string,
files: File[],
fetch: (...args: unknown[]) => void,
) {
const importTasks = files.map((f) => {
const formData = new FormData();
formData.append('file', f);
return api.post('/product/import-product', formData, {
params: { productGroupId },
});
});
await Promise.all(importTasks);
fetch?.();
}
async function fetchListProductById(productId: string) { async function fetchListProductById(productId: string) {
const res = await api.get<Product>(`/product/${productId}`); const res = await api.get<Product>(`/product/${productId}`);
@ -549,6 +566,8 @@ const useProductServiceStore = defineStore('api-product-service', () => {
fetchImageListById, fetchImageListById,
addImageList, addImageList,
deleteImageByName, deleteImageByName,
importProduct,
}; };
}); });