changes
This commit is contained in:
3
app/components/imports/AddOS.vue
Normal file
3
app/components/imports/AddOS.vue
Normal file
@@ -0,0 +1,3 @@
|
||||
<script lang="ts" setup></script>
|
||||
|
||||
<template>AddOS</template>
|
||||
264
app/components/imports/AddProductForm.vue
Normal file
264
app/components/imports/AddProductForm.vue
Normal file
@@ -0,0 +1,264 @@
|
||||
<script setup>
|
||||
const { $insertapi } = useNuxtApp();
|
||||
|
||||
const isPending = ref(false);
|
||||
const body = 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,
|
||||
});
|
||||
|
||||
function selected(field, data) {
|
||||
body.value[field] = data.id;
|
||||
}
|
||||
|
||||
async function createProduct() {
|
||||
isPending.value = true;
|
||||
const res = await $insertapi("product", body.value);
|
||||
isPending.value = false;
|
||||
}
|
||||
|
||||
/* TODO: <SearchBox> addons */
|
||||
const addOS = {
|
||||
component: "imports/AddOS",
|
||||
width: "60%",
|
||||
height: "auto",
|
||||
title: "AddOS",
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1 class="subtitle is-4">AddProductForm</h1>
|
||||
<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,
|
||||
placeholder: 'OS',
|
||||
}"
|
||||
@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,
|
||||
placeholder: '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,
|
||||
placeholder: '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: 'code',
|
||||
column: ['code'],
|
||||
first: true,
|
||||
placeholder: '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,
|
||||
placeholder: '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,
|
||||
placeholder: '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,
|
||||
placeholder: '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,
|
||||
placeholder: '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,
|
||||
placeholder: '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,
|
||||
placeholder: '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,
|
||||
placeholder: '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,
|
||||
placeholder: '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,
|
||||
placeholder: '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="Object.values(body).every((v) => v === null)"
|
||||
@click.prevent="createProduct"
|
||||
>
|
||||
Tạo sản phẩm
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
134
app/components/imports/AddProductVariantForm.vue
Normal file
134
app/components/imports/AddProductVariantForm.vue
Normal file
@@ -0,0 +1,134 @@
|
||||
<script setup>
|
||||
import InputNumber from "@/components/common/InputNumber.vue";
|
||||
|
||||
const { $insertapi } = useNuxtApp();
|
||||
|
||||
const isPending = ref(false);
|
||||
const body = ref({
|
||||
product: null,
|
||||
price: null,
|
||||
internal_storage: null,
|
||||
ram: null,
|
||||
color: null,
|
||||
note: null,
|
||||
});
|
||||
|
||||
function selected(field, data) {
|
||||
if (field === "price") {
|
||||
body.value[field] = data;
|
||||
} else {
|
||||
body.value[field] = data.id;
|
||||
}
|
||||
}
|
||||
|
||||
async function createProductVariant() {
|
||||
isPending.value = true;
|
||||
const res = await $insertapi("Product_Variant", body.value);
|
||||
isPending.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1 class="subtitle is-4">AddProductVariantForm</h1>
|
||||
<form class="fixed-grid has-12-cols">
|
||||
<div class="grid">
|
||||
<div class="cell is-col-span-8">
|
||||
<div class="field">
|
||||
<label class="label">Sản phẩm</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'product',
|
||||
field: 'name',
|
||||
column: ['name'],
|
||||
first: true,
|
||||
placeholder: 'Sản phẩm',
|
||||
}"
|
||||
@option="selected('product', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">Đơn giá</label>
|
||||
<div class="control">
|
||||
<InputNumber
|
||||
v-bind="{
|
||||
record: body,
|
||||
attr: 'price',
|
||||
placeholder: 'Đơn giá',
|
||||
}"
|
||||
@number="selected('price', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">Màu sắc</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'color',
|
||||
field: 'name',
|
||||
column: ['name'],
|
||||
first: true,
|
||||
placeholder: 'Màu sắc',
|
||||
}"
|
||||
@option="selected('color', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">RAM</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'RAM',
|
||||
field: 'code',
|
||||
column: ['code'],
|
||||
first: true,
|
||||
placeholder: 'RAM',
|
||||
}"
|
||||
@option="selected('ram', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-4">
|
||||
<div class="field">
|
||||
<label class="label">Bộ nhớ trong</label>
|
||||
<SearchBox
|
||||
v-bind="{
|
||||
api: 'internalstorage',
|
||||
field: 'code',
|
||||
column: ['code'],
|
||||
first: true,
|
||||
placeholder: 'Bộ nhớ trong',
|
||||
}"
|
||||
@option="selected('internal_storage', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell is-col-span-12">
|
||||
<div class="field">
|
||||
<label class="label">Ghi chú</label>
|
||||
<textarea
|
||||
v-model.trim="body.note"
|
||||
class="textarea"
|
||||
name="note"
|
||||
placeholder="Ghi chú"
|
||||
rows="2"
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cell is-col-span-12">
|
||||
<button
|
||||
:class="['button is-primary', { 'is-loading': isPending }]"
|
||||
:disabled="Object.values(body).every((v) => v === null)"
|
||||
@click.prevent="createProductVariant"
|
||||
>
|
||||
Thêm phiên bản
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
@@ -1,38 +1,8 @@
|
||||
<script setup>
|
||||
import AddProductForm from "@/components/imports/AddProductForm.vue";
|
||||
import AddProductVariantForm from "@/components/imports/AddProductVariantForm.vue";
|
||||
import FileUpload from "@/components/media/FileUpload.vue";
|
||||
|
||||
const { $getdata } = useNuxtApp();
|
||||
const files = ref([]);
|
||||
|
||||
onMounted(async () => {
|
||||
const filesFetched = await $getdata("file", {
|
||||
id__gte: 12473,
|
||||
id__lte: 12475,
|
||||
});
|
||||
|
||||
files.value = filesFetched;
|
||||
});
|
||||
|
||||
async function onClick(url) {
|
||||
const blob = await $fetch("/api/hello", {
|
||||
query: { url },
|
||||
responseType: "blob",
|
||||
});
|
||||
const urlDownload = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.href = urlDownload;
|
||||
link.setAttribute("download", "aName");
|
||||
link.click();
|
||||
link.remove();
|
||||
}
|
||||
|
||||
const buildUrl = (f) => `https://api.utopia.com.vn/download?name=${f.file}&type=file`;
|
||||
|
||||
function onFiles(files) {
|
||||
console.log("files", toRaw(files));
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FileUpload
|
||||
:type="['file']"
|
||||
@@ -47,20 +17,6 @@ function onFiles(files) {
|
||||
</template>
|
||||
<span class="font-medium">Import</span>
|
||||
</FileUpload>
|
||||
<div class="buttons">
|
||||
<button
|
||||
class="button"
|
||||
v-for="(url, i) in files.map(buildUrl)"
|
||||
:key="i"
|
||||
@click="onClick(url)"
|
||||
>
|
||||
<span class="icon">
|
||||
<Icon
|
||||
name="material-symbols:download-rounded"
|
||||
:size="18"
|
||||
/>
|
||||
</span>
|
||||
<span>{{ files[i].name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<AddProductVariantForm />
|
||||
<AddProductForm />
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user