changes
This commit is contained in:
81
app/components/imports/AddIMEIForm.vue
Normal file
81
app/components/imports/AddIMEIForm.vue
Normal file
@@ -0,0 +1,81 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
variant: Object,
|
||||
});
|
||||
|
||||
const { $empty, $insertapi } = useNuxtApp();
|
||||
const emit = defineEmits(["created"]);
|
||||
const isLoading = ref(false);
|
||||
const body = ref({
|
||||
imei: null,
|
||||
variant: props.variant.id,
|
||||
});
|
||||
|
||||
async function submit() {
|
||||
isLoading.value = true;
|
||||
const res = await $insertapi("IMEI", body.value);
|
||||
isLoading.value = false;
|
||||
if (res !== "error") {
|
||||
emit("created");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form class="fixed-grid has-12-cols">
|
||||
<div class="grid">
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">Variant</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'Product_Variant',
|
||||
field: 'code',
|
||||
column: ['code'],
|
||||
optionid: variant.id,
|
||||
disabled: true,
|
||||
first: true,
|
||||
placeholder: 'Variant',
|
||||
}"
|
||||
@option="body.variant = $event?.id ?? $event"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-6">
|
||||
<div class="field">
|
||||
<label class="label">IMEI</label>
|
||||
<div class="control">
|
||||
<input
|
||||
v-model.trim="body.imei"
|
||||
type="text"
|
||||
class="input"
|
||||
placeholder="IMEI"
|
||||
maxlength="15"
|
||||
/>
|
||||
</div>
|
||||
<p class="help is-info">15 chữ số</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-2">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<label class="label is-invisible">Submit</label>
|
||||
<button
|
||||
:class="['button is-primary is-fullwidth', isLoading && 'is-loading']"
|
||||
:disabled="$empty(body.imei) || body.imei.length !== 15"
|
||||
@click.prevent="submit"
|
||||
>
|
||||
<span class="icon">
|
||||
<Icon
|
||||
name="material-symbols:add-rounded"
|
||||
:size="18"
|
||||
/>
|
||||
</span>
|
||||
<span>Thêm</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
@@ -45,7 +45,7 @@ watch(product, () => {
|
||||
pagename: 'product-variants',
|
||||
params: {
|
||||
values:
|
||||
'id,code,product,product__name,color,color__code,color__name,color__hex_code,ram,ram__code,ram__capacity,internal_storage,internal_storage__code,internal_storage__capacity,image,price,note,create_time,update_time',
|
||||
'id,code,product,product__name,color,color__code,color__name,color__hex_code,ram,ram__code,ram__capacity,internal_storage,internal_storage__code,internal_storage__capacity,image,image__path,price,note,create_time,update_time',
|
||||
filter: { product: product.id },
|
||||
sort: 'id',
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup>
|
||||
import InputNumber from "@/components/common/InputNumber.vue";
|
||||
import FileUpload from "@/components/media/FileUpload.vue";
|
||||
import { omitBy } from "es-toolkit";
|
||||
|
||||
const props = defineProps({
|
||||
@@ -8,7 +9,7 @@ const props = defineProps({
|
||||
|
||||
const emit = defineEmits(["created"]);
|
||||
|
||||
const { $empty, $insertapi } = useNuxtApp();
|
||||
const { $buildFileUrl, $empty, $insertapi } = useNuxtApp();
|
||||
const isPending = ref(false);
|
||||
const body = ref({
|
||||
product: props.productId,
|
||||
@@ -16,13 +17,16 @@ const body = ref({
|
||||
internal_storage: null,
|
||||
ram: null,
|
||||
color: null,
|
||||
image: null,
|
||||
note: "",
|
||||
});
|
||||
|
||||
const uploadedImage = ref();
|
||||
|
||||
watch(
|
||||
() => props.productId,
|
||||
(newVal) => {
|
||||
body.value.product = props.productId;
|
||||
body.value.product = newVal;
|
||||
},
|
||||
);
|
||||
|
||||
@@ -34,8 +38,22 @@ function selected(field, data) {
|
||||
}
|
||||
}
|
||||
|
||||
function onFiles(files) {
|
||||
const file = files[0];
|
||||
uploadedImage.value = file;
|
||||
}
|
||||
|
||||
async function createProductVariant() {
|
||||
isPending.value = true;
|
||||
|
||||
// 1. insert row to Product_Image, get back id
|
||||
const productImage = await $insertapi("Product_Image", {
|
||||
name: uploadedImage.value.name,
|
||||
path: $buildFileUrl(uploadedImage.value.file),
|
||||
});
|
||||
body.value.image = productImage.id;
|
||||
|
||||
// 2. upload to Product_Variant table
|
||||
const trimmedBody = omitBy(body.value, $empty);
|
||||
const res = await $insertapi("Product_Variant", trimmedBody);
|
||||
isPending.value = false;
|
||||
@@ -132,7 +150,7 @@ async function createProductVariant() {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-12">
|
||||
<div class="cell is-col-span-6">
|
||||
<div class="field">
|
||||
<label class="label">Ghi chú</label>
|
||||
<textarea
|
||||
@@ -140,10 +158,65 @@ async function createProductVariant() {
|
||||
class="textarea"
|
||||
name="note"
|
||||
placeholder="Ghi chú"
|
||||
rows="1"
|
||||
rows="5"
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-6">
|
||||
<div class="field">
|
||||
<label class="label">Hình ảnh</label>
|
||||
<div class="control is-flex is-gap-1">
|
||||
<div>
|
||||
<div
|
||||
v-if="uploadedImage"
|
||||
class="relative"
|
||||
style="border: 1px solid var(--bulma-grey-50)"
|
||||
>
|
||||
<figure class="image is-128x128">
|
||||
<img :src="$buildFileUrl(uploadedImage.file)" />
|
||||
</figure>
|
||||
<button
|
||||
type="button"
|
||||
class="button is-small is-danger is-light absolute"
|
||||
:style="{ top: '5px', right: '5px' }"
|
||||
@click="uploadedImage = undefined"
|
||||
>
|
||||
<span class="icon">
|
||||
<Icon
|
||||
name="material-symbols:delete-outline-rounded"
|
||||
:size="20"
|
||||
/>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="w-36 h-36 rounded-md is-flex is-align-items-center is-justify-content-center"
|
||||
style="border: 1px solid var(--bulma-grey-80)"
|
||||
>
|
||||
<Icon
|
||||
name="material-symbols:add-photo-alternate-outline-rounded"
|
||||
:size="40"
|
||||
class="has-text-grey-light"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<FileUpload
|
||||
:type="['image']"
|
||||
:multiple="false"
|
||||
@files="onFiles"
|
||||
>
|
||||
<template #icon>
|
||||
<Icon
|
||||
name="material-symbols:add-photo-alternate-outline-rounded"
|
||||
:size="20"
|
||||
/>
|
||||
</template>
|
||||
<span class="font-medium">Chọn</span>
|
||||
</FileUpload>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-12">
|
||||
<button
|
||||
:class="['button is-primary', { 'is-loading': isPending }]"
|
||||
|
||||
50
app/components/imports/DeleteProductVariant.vue
Normal file
50
app/components/imports/DeleteProductVariant.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<script setup>
|
||||
import Modal from "@/components/Modal.vue";
|
||||
|
||||
const props = defineProps({
|
||||
variant: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["dynamicCompEvent"]);
|
||||
const { $deleteapi } = useNuxtApp();
|
||||
const showConfirmModal = ref(null);
|
||||
|
||||
function displayModal() {
|
||||
showConfirmModal.value = {
|
||||
component: "dialog/Confirm",
|
||||
title: "Xoá phiên bản",
|
||||
width: "500px",
|
||||
height: "auto",
|
||||
vbind: {
|
||||
content: `Bạn xác nhận xoá phiên bản <code>${props.variant.code}</code>?`,
|
||||
onModalevent: deleteVariant,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function deleteVariant() {
|
||||
const res = await $deleteapi("Product_Variant", props.variant.id);
|
||||
if (res !== "error") {
|
||||
// emit to parent, which is DataTable
|
||||
emit("dynamicCompEvent", { type: "refresh" });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a
|
||||
class="has-text-danger"
|
||||
@click="displayModal"
|
||||
>
|
||||
<span class="icon">
|
||||
<Icon
|
||||
name="material-symbols:delete-outline-rounded"
|
||||
:size="18"
|
||||
/>
|
||||
</span>
|
||||
<Modal
|
||||
v-bind="showConfirmModal"
|
||||
@close="showConfirmModal = null"
|
||||
/>
|
||||
</a>
|
||||
</template>
|
||||
32
app/components/imports/IMEIButton.vue
Normal file
32
app/components/imports/IMEIButton.vue
Normal file
@@ -0,0 +1,32 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
variant: Object,
|
||||
});
|
||||
const showModal = ref(null);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
@click="
|
||||
showModal = {
|
||||
component: 'imports/IMEIs',
|
||||
title: 'IMEIs',
|
||||
width: '80%',
|
||||
height: '400px',
|
||||
vbind: { variant: props.variant },
|
||||
}
|
||||
"
|
||||
class="button is-small is-primary is-ghost"
|
||||
>
|
||||
<span class="icon">
|
||||
<Icon
|
||||
name="mdi:launch"
|
||||
:size="22"
|
||||
/>
|
||||
</span>
|
||||
</button>
|
||||
<Modal
|
||||
v-bind="showModal"
|
||||
@close="showModal = null"
|
||||
/>
|
||||
</template>
|
||||
40
app/components/imports/IMEIs.vue
Normal file
40
app/components/imports/IMEIs.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<script setup>
|
||||
import DataView from "@/components/datatable/DataView.vue";
|
||||
import AddIMEIForm from "@/components/imports/AddIMEIForm.vue";
|
||||
import ImportData from "@/components/parameter/ImportData.vue";
|
||||
|
||||
const props = defineProps({
|
||||
variant: Object,
|
||||
});
|
||||
const emit = defineEmits(["close"]);
|
||||
const key = ref(0);
|
||||
</script>
|
||||
<template>
|
||||
<div class="block">
|
||||
<DataView
|
||||
:key="key"
|
||||
v-bind="{
|
||||
api: 'IMEI',
|
||||
setting: 'imeis',
|
||||
pagename: 'imeis',
|
||||
params: {
|
||||
values: 'id,code,imei,variant,variant__code,create_time,update_time',
|
||||
filter: { variant: variant.id },
|
||||
sort: 'id',
|
||||
},
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
<div class="block">
|
||||
<AddIMEIForm
|
||||
:variant="variant"
|
||||
@created="key++"
|
||||
/>
|
||||
</div>
|
||||
<div class="block">
|
||||
<ImportData
|
||||
code="imeis"
|
||||
@close="key++"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
11
app/components/imports/ProductImage.vue
Normal file
11
app/components/imports/ProductImage.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
variant: Object,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<figure class="image is-32x32">
|
||||
<img :src="variant.image__path" />
|
||||
</figure>
|
||||
</template>
|
||||
Reference in New Issue
Block a user