changes
This commit is contained in:
422
app/components/imports/ProductForm.vue
Normal file
422
app/components/imports/ProductForm.vue
Normal file
@@ -0,0 +1,422 @@
|
||||
<script setup>
|
||||
import { isEqual } from "es-toolkit";
|
||||
|
||||
const props = defineProps({
|
||||
variantId: Number,
|
||||
});
|
||||
|
||||
const { $copy, $getdata, $insertapi, $patchapi } = useNuxtApp();
|
||||
|
||||
const isPending = ref(false);
|
||||
const defaultBody = ref({
|
||||
name: null,
|
||||
manufacturer: null,
|
||||
os: null,
|
||||
battery: null,
|
||||
screen: null,
|
||||
cpu: null,
|
||||
gpu: null,
|
||||
camera_system: null,
|
||||
sim: null,
|
||||
network_technology: null,
|
||||
charging_technology: null,
|
||||
external_storage: null,
|
||||
ip_rating: null,
|
||||
design: null,
|
||||
});
|
||||
|
||||
const body = ref($copy(defaultBody.value));
|
||||
|
||||
const productVariant = ref();
|
||||
onMounted(async () => {
|
||||
if (props.variantId) {
|
||||
const variant = await $getdata(
|
||||
"Product_Variant",
|
||||
undefined,
|
||||
{
|
||||
filter: { id: props.variantId },
|
||||
values:
|
||||
"id,code,product,product__name,product__os,product__manufacturer,product__battery,product__screen,product__cpu,product__gpu,product__camera_system,product__sim,product__network_technology,product__charging_technology,product__external_storage,product__ip_rating,product__design,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",
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
productVariant.value = variant;
|
||||
|
||||
defaultBody.value = {
|
||||
name: variant.product__name,
|
||||
manufacturer: variant.product__manufacturer,
|
||||
os: variant.product__os,
|
||||
battery: variant.product__battery,
|
||||
screen: variant.product__screen,
|
||||
cpu: variant.product__cpu,
|
||||
gpu: variant.product__gpu,
|
||||
camera_system: variant.product__camera_system,
|
||||
sim: variant.product__sim,
|
||||
network_technology: variant.product__network_technology,
|
||||
charging_technology: variant.product__charging_technology,
|
||||
external_storage: variant.product__external_storage,
|
||||
ip_rating: variant.product__ip_rating,
|
||||
design: variant.product__design,
|
||||
};
|
||||
|
||||
body.value = $copy(defaultBody.value);
|
||||
}
|
||||
});
|
||||
|
||||
const isDirty = computed(() => !isEqual(body.value, defaultBody.value));
|
||||
|
||||
function selected(field, data) {
|
||||
if (data === null) body.value[field] = data;
|
||||
else body.value[field] = data.id;
|
||||
}
|
||||
|
||||
const refreshData = inject("refreshData");
|
||||
async function submit() {
|
||||
isPending.value = true;
|
||||
const res = props.variantId
|
||||
? await $patchapi("product", {
|
||||
id: productVariant.value.product,
|
||||
...body.value,
|
||||
})
|
||||
: await $insertapi("product", body.value);
|
||||
if (res !== "error") {
|
||||
if (refreshData) refreshData();
|
||||
}
|
||||
isPending.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form class="fixed-grid has-12-cols">
|
||||
<div class="grid">
|
||||
<div class="cell is-col-span-8">
|
||||
<div class="field">
|
||||
<label class="label">Tên sản phẩm</label>
|
||||
<div class="control">
|
||||
<input
|
||||
class="input"
|
||||
v-model.trim="body.name"
|
||||
type="text"
|
||||
placeholder="Tên"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">OS</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'OS',
|
||||
field: 'name',
|
||||
column: ['name'],
|
||||
first: true,
|
||||
clearable: true,
|
||||
optionid: body.os,
|
||||
placeholder: 'OS',
|
||||
addon: {
|
||||
component: 'imports/addons/AddOS',
|
||||
width: '70%',
|
||||
height: 'auto',
|
||||
title: 'Thêm hệ điều hành',
|
||||
},
|
||||
}"
|
||||
@option="selected('os', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">Hãng</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'Manufacturer',
|
||||
field: 'name',
|
||||
column: ['name'],
|
||||
first: true,
|
||||
clearable: true,
|
||||
optionid: body.manufacturer,
|
||||
placeholder: 'Hãng',
|
||||
addon: {
|
||||
component: 'imports/addons/AddManufacturer',
|
||||
width: '70%',
|
||||
height: 'auto',
|
||||
title: 'Thêm hãng',
|
||||
},
|
||||
}"
|
||||
@option="selected('manufacturer', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">Pin</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'Battery',
|
||||
field: 'code',
|
||||
column: ['code'],
|
||||
first: true,
|
||||
clearable: true,
|
||||
optionid: body.battery,
|
||||
placeholder: 'Pin',
|
||||
addon: {
|
||||
component: 'imports/addons/AddBattery',
|
||||
width: '70%',
|
||||
height: 'auto',
|
||||
title: 'Thêm pin',
|
||||
},
|
||||
}"
|
||||
@option="selected('battery', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">Màn hình</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'Screen',
|
||||
field: 'label',
|
||||
column: ['resolution', 'standard', 'technology'],
|
||||
first: true,
|
||||
clearable: true,
|
||||
optionid: body.screen,
|
||||
placeholder: 'Màn hình',
|
||||
addon: {
|
||||
component: 'imports/addons/AddScreen',
|
||||
width: '70%',
|
||||
height: 'auto',
|
||||
title: 'Thêm màn hình',
|
||||
},
|
||||
}"
|
||||
@option="selected('screen', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">CPU</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'CPU',
|
||||
field: 'name',
|
||||
column: ['name'],
|
||||
first: true,
|
||||
clearable: true,
|
||||
placeholder: 'CPU',
|
||||
optionid: body.cpu,
|
||||
addon: {
|
||||
component: 'imports/addons/AddCPU',
|
||||
width: '70%',
|
||||
height: 'auto',
|
||||
title: 'Thêm CPU',
|
||||
},
|
||||
}"
|
||||
@option="selected('cpu', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">GPU</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'GPU',
|
||||
field: 'name',
|
||||
column: ['name'],
|
||||
first: true,
|
||||
clearable: true,
|
||||
optionid: body.gpu,
|
||||
placeholder: 'GPU',
|
||||
addon: {
|
||||
component: 'imports/addons/AddGPU',
|
||||
width: '70%',
|
||||
height: 'auto',
|
||||
title: 'Thêm GPU',
|
||||
},
|
||||
}"
|
||||
@option="selected('gpu', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">Camera</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'Camera_System',
|
||||
field: 'code',
|
||||
column: ['code'],
|
||||
first: true,
|
||||
clearable: true,
|
||||
optionid: body.camera_system,
|
||||
placeholder: 'Camera',
|
||||
addon: {
|
||||
component: 'imports/addons/AddCamera',
|
||||
width: '70%',
|
||||
height: 'auto',
|
||||
title: 'Thêm camera',
|
||||
},
|
||||
}"
|
||||
@option="selected('camera_system', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">SIM</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'SIM',
|
||||
field: 'code',
|
||||
column: ['code'],
|
||||
first: true,
|
||||
clearable: true,
|
||||
optionid: body.sim,
|
||||
placeholder: 'SIM',
|
||||
addon: {
|
||||
component: 'imports/addons/AddSIM',
|
||||
width: '70%',
|
||||
height: 'auto',
|
||||
title: 'Thêm SIM',
|
||||
},
|
||||
}"
|
||||
@option="selected('sim', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">Kết nối</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'Network_Technology',
|
||||
field: 'name',
|
||||
column: ['name'],
|
||||
first: true,
|
||||
clearable: true,
|
||||
optionid: body.network_technology,
|
||||
placeholder: 'Kết nối',
|
||||
addon: {
|
||||
component: 'imports/addons/AddNetworkTechnology',
|
||||
width: '70%',
|
||||
height: 'auto',
|
||||
title: 'Thêm kết nối',
|
||||
},
|
||||
}"
|
||||
@option="selected('network_technology', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">Công nghệ sạc</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'Charging_Technology',
|
||||
field: 'code',
|
||||
column: ['code'],
|
||||
first: true,
|
||||
clearable: true,
|
||||
optionid: body.charging_technology,
|
||||
placeholder: 'Công nghệ sạc',
|
||||
addon: {
|
||||
component: 'imports/addons/AddChargingTechnology',
|
||||
width: '70%',
|
||||
height: 'auto',
|
||||
title: 'Thêm công nghệ sạc',
|
||||
},
|
||||
}"
|
||||
@option="selected('charging_technology', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">Bộ nhớ ngoài</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'External_Storage',
|
||||
field: 'code',
|
||||
column: ['code'],
|
||||
first: true,
|
||||
clearable: true,
|
||||
optionid: body.external_storage,
|
||||
placeholder: 'Bộ nhớ ngoài',
|
||||
position: 'is-top-right',
|
||||
addon: {
|
||||
component: 'imports/addons/AddExternalStorage',
|
||||
width: '70%',
|
||||
height: 'auto',
|
||||
title: 'Thêm bộ nhớ ngoài',
|
||||
},
|
||||
}"
|
||||
@option="selected('external_storage', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">Chỉ số IP</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'IP_Rating',
|
||||
field: 'name',
|
||||
column: ['name'],
|
||||
first: true,
|
||||
clearable: true,
|
||||
optionid: body.ip_rating,
|
||||
placeholder: 'Chỉ số IP',
|
||||
position: 'is-top-right',
|
||||
addon: {
|
||||
component: 'imports/addons/AddIPRating',
|
||||
width: '70%',
|
||||
height: 'auto',
|
||||
title: 'Thêm chỉ số IP',
|
||||
},
|
||||
}"
|
||||
@option="selected('ip_rating', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">Chất liệu</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'Design',
|
||||
field: 'label',
|
||||
column: ['frame_material', 'back_material'],
|
||||
first: true,
|
||||
clearable: true,
|
||||
optionid: body.design,
|
||||
placeholder: 'Chất liệu',
|
||||
position: 'is-top-right',
|
||||
addon: {
|
||||
component: 'imports/addons/AddDesign',
|
||||
width: '70%',
|
||||
height: 'auto',
|
||||
title: 'Thêm chất liệu',
|
||||
},
|
||||
}"
|
||||
@option="selected('design', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-12">
|
||||
<button
|
||||
:class="['button is-primary', { 'is-loading': isPending }]"
|
||||
:disabled="!isDirty"
|
||||
@click.prevent="submit"
|
||||
>
|
||||
<span class="icon">
|
||||
<Icon :name="variantId ? 'material-symbols:edit-outline-rounded' : 'material-symbols:add-rounded'" />
|
||||
</span>
|
||||
<span>{{ variantId ? "Cập nhật" : "Tạo" }} sản phẩm</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
Reference in New Issue
Block a user