changes
This commit is contained in:
@@ -22,22 +22,15 @@
|
|||||||
v-if="title"
|
v-if="title"
|
||||||
class="modal-card-head px-4 py-3"
|
class="modal-card-head px-4 py-3"
|
||||||
>
|
>
|
||||||
<div class="w-full">
|
|
||||||
<div class="field is-grouped is-align-items-center">
|
|
||||||
<div class="control is-expanded has-text-left">
|
|
||||||
<p
|
<p
|
||||||
class="fs-17 font-semibold has-text-primary"
|
class="fs-17 font-semibold has-text-primary control is-expanded has-text-left modal-card-title"
|
||||||
v-html="title"
|
v-html="title"
|
||||||
></p>
|
></p>
|
||||||
</div>
|
|
||||||
<div class="control has-text-right">
|
|
||||||
<button
|
<button
|
||||||
class="delete is-medium"
|
class="delete is-medium"
|
||||||
|
aria-label="close"
|
||||||
@click="closeModal()"
|
@click="closeModal()"
|
||||||
></button>
|
></button>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
</header>
|
||||||
<section
|
<section
|
||||||
class="modal-card-body p-4"
|
class="modal-card-body p-4"
|
||||||
@@ -104,7 +97,7 @@ const docid = $id();
|
|||||||
let count = 0;
|
let count = 0;
|
||||||
const lock = false;
|
const lock = false;
|
||||||
|
|
||||||
const closeModal = function () {
|
const closeModal = () => {
|
||||||
if (!lock) emit("close");
|
if (!lock) emit("close");
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -129,7 +122,8 @@ const doClick = function (e) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (Object.values(props).some((x) => isNotNil(x))) {
|
const modalHasProps = Object.values(props).some((x) => isNotNil(x));
|
||||||
|
if (modalHasProps) {
|
||||||
document.documentElement.classList.add("is-clipped");
|
document.documentElement.classList.add("is-clipped");
|
||||||
window.addEventListener("keydown", (e) => {
|
window.addEventListener("keydown", (e) => {
|
||||||
if (e.key === "Escape") closeModal();
|
if (e.key === "Escape") closeModal();
|
||||||
|
|||||||
@@ -34,13 +34,13 @@
|
|||||||
<span class="icon is-left">
|
<span class="icon is-left">
|
||||||
<Icon
|
<Icon
|
||||||
name="material-symbols:search"
|
name="material-symbols:search"
|
||||||
:size="22"
|
:size="20"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span class="icon is-right">
|
<span class="icon is-right">
|
||||||
<Icon
|
<Icon
|
||||||
name="material-symbols:keyboard-arrow-down-rounded"
|
name="material-symbols:keyboard-arrow-down-rounded"
|
||||||
:size="22"
|
:size="20"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -54,14 +54,8 @@
|
|||||||
class="dropdown-content px-3"
|
class="dropdown-content px-3"
|
||||||
style="min-width: 100%"
|
style="min-width: 100%"
|
||||||
>
|
>
|
||||||
<p
|
|
||||||
v-if="data.length === 0"
|
|
||||||
class="has-text-grey px-2 py-1"
|
|
||||||
>
|
|
||||||
{{ isVietnamese ? "Không có giá trị thỏa mãn" : "No matching values" }}
|
|
||||||
</p>
|
|
||||||
<ScrollBox
|
<ScrollBox
|
||||||
v-else
|
v-if="data.length > 0"
|
||||||
v-bind="{
|
v-bind="{
|
||||||
data: data,
|
data: data,
|
||||||
name: field,
|
name: field,
|
||||||
@@ -71,34 +65,55 @@
|
|||||||
}"
|
}"
|
||||||
@selected="choose"
|
@selected="choose"
|
||||||
/>
|
/>
|
||||||
|
<p
|
||||||
|
v-else
|
||||||
|
class="has-text-grey px-2 py-1"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
v-if="isLoading"
|
||||||
|
name="svg-spinners:90-ring"
|
||||||
|
:size="22"
|
||||||
|
/>
|
||||||
|
<span v-else>Không có giá trị thoả mãn</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="control"
|
|
||||||
v-if="clearable && value"
|
v-if="clearable && value"
|
||||||
|
class="control"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="button is-primary px-2"
|
class="button is-light"
|
||||||
@click="clearValue"
|
@click="clearValue"
|
||||||
style="height: 100%"
|
style="height: 100%"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<SvgIcon v-bind="{ name: 'close.svg', type: 'white', size: 24 }"></SvgIcon>
|
<span class="icon">
|
||||||
|
<Icon
|
||||||
|
name="material-symbols:close-rounded"
|
||||||
|
:size="16"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="control"
|
|
||||||
v-if="viewaddon"
|
v-if="viewaddon"
|
||||||
|
class="control"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="button is-dark px-2"
|
class="button is-primary is-light"
|
||||||
@click="viewInfo()"
|
@click="viewInfo()"
|
||||||
style="height: 100%"
|
style="height: 100%"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<SvgIcon v-bind="{ name: 'view.svg', type: 'white', size: 24 }"></SvgIcon>
|
<span class="icon">
|
||||||
|
<Icon
|
||||||
|
name="material-symbols:visibility-rounded"
|
||||||
|
:size="20"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -106,15 +121,15 @@
|
|||||||
v-if="addon"
|
v-if="addon"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="button is-primary"
|
class="button is-success is-light"
|
||||||
@click="addNew()"
|
@click="addNew()"
|
||||||
style="height: 100%"
|
style="height: 100%"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<Icon
|
<Icon
|
||||||
name="material-symbols:add-2-rounded"
|
name="material-symbols:add-rounded"
|
||||||
:size="22"
|
:size="18"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -124,8 +139,7 @@
|
|||||||
@dataevent="dataevent"
|
@dataevent="dataevent"
|
||||||
@close="showmodal = undefined"
|
@close="showmodal = undefined"
|
||||||
v-bind="showmodal"
|
v-bind="showmodal"
|
||||||
v-if="showmodal"
|
/>
|
||||||
></Modal>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -157,6 +171,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
search: undefined,
|
search: undefined,
|
||||||
data: [],
|
data: [],
|
||||||
|
isLoading: false,
|
||||||
timer: undefined,
|
timer: undefined,
|
||||||
value: undefined,
|
value: undefined,
|
||||||
selected: undefined,
|
selected: undefined,
|
||||||
@@ -266,8 +281,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async getData() {
|
async getData() {
|
||||||
|
this.isLoading = false;
|
||||||
this.params.filter = this.filter;
|
this.params.filter = this.filter;
|
||||||
let data = await this.$getdata(this.api, undefined, this.params);
|
let data = await this.$getdata(this.api, undefined, this.params);
|
||||||
|
this.isLoading = true;
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
async getApi(val) {
|
async getApi(val) {
|
||||||
@@ -373,4 +390,11 @@ export default {
|
|||||||
.field:not(:last-child) {
|
.field:not(:last-child) {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
.button.is-light {
|
||||||
|
--bulma-button-background-l: 89%;
|
||||||
|
}
|
||||||
|
.button:hover,
|
||||||
|
.button.is-hovered {
|
||||||
|
--bulma-button-background-l-delta: -10%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="control has-icons-left">
|
<div class="field has-addons">
|
||||||
|
<p class="control has-icons-left has-icons-right is-expanded">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
v-model="value"
|
v-model="value"
|
||||||
|
@keyup="doCheck"
|
||||||
:class="['input', disabled && 'has-text-black']"
|
:class="['input', disabled && 'has-text-black']"
|
||||||
:placeholder="placeholder || ''"
|
:placeholder="placeholder || ''"
|
||||||
@keyup="doCheck"
|
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
/>
|
/>
|
||||||
<span class="icon is-left">
|
<span class="icon is-left">
|
||||||
@@ -14,11 +15,20 @@
|
|||||||
:size="22"
|
:size="22"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
v-if="unit"
|
||||||
|
class="control"
|
||||||
|
>
|
||||||
|
<a class="button is-static fs-12 h-full">
|
||||||
|
{{ unit }}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ["record", "attr", "placeholder", "disabled", "defaultValue"],
|
props: ["record", "attr", "placeholder", "disabled", "defaultValue", "unit"],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
value: this.getInitialValue(),
|
value: this.getInitialValue(),
|
||||||
|
|||||||
@@ -192,7 +192,7 @@
|
|||||||
>
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<Icon
|
<Icon
|
||||||
name="material-symbols:add-2-rounded"
|
name="material-symbols:add-rounded"
|
||||||
:size="22"
|
:size="22"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
@@ -210,7 +210,7 @@
|
|||||||
>
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<Icon
|
<Icon
|
||||||
name="material-symbols:settings-outline-rounded"
|
name="material-symbols:table-edit-outline"
|
||||||
:size="22"
|
:size="22"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
@@ -240,8 +240,8 @@
|
|||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="tabs is-toggle">
|
<div class="tabs is-toggle is-centered">
|
||||||
<ul class="is-flex-grow-0 mx-auto">
|
<ul>
|
||||||
<li
|
<li
|
||||||
v-for="(v, i) in getMenu().filter((x) =>
|
v-for="(v, i) in getMenu().filter((x) =>
|
||||||
currentField.format === 'number'
|
currentField.format === 'number'
|
||||||
@@ -254,32 +254,31 @@
|
|||||||
:class="selectTab.code === v.code ? 'is-active' : 'has-text-primary'"
|
:class="selectTab.code === v.code ? 'is-active' : 'has-text-primary'"
|
||||||
@click="changeTab(v)"
|
@click="changeTab(v)"
|
||||||
>
|
>
|
||||||
<a class="px-4 py-1.5">{{ v.name }}</a>
|
<a class="px-8 py-1.5 fs-14">{{ v.name }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="currentTab === 'detail'">
|
<div v-if="currentTab === 'detail'">
|
||||||
<p class="fs-14 mt-3">
|
<div class="fs-14 mt-3 is-flex is-gap-0.5 is-align-items-center">
|
||||||
<strong> Tên trường: </strong> {{ currentField.name }}
|
<p class="font-semibold">Tên trường:</p>
|
||||||
<a @click="copyContent(currentField.name)">
|
<p>{{ currentField.name }}</p>
|
||||||
<span class="tooltip">
|
<button
|
||||||
<SvgIcon
|
class="button is-white is-small"
|
||||||
class="ml-1"
|
@click="copyContent(currentField.name)"
|
||||||
v-bind="{ name: 'copy.svg', type: 'primary', size: 16 }"
|
|
||||||
></SvgIcon>
|
|
||||||
<span
|
|
||||||
class="tooltiptext"
|
|
||||||
style="top: 110%; bottom: unset; min-width: max-content; left: 25px"
|
|
||||||
>Copy</span
|
|
||||||
>
|
>
|
||||||
|
<span class="icon">
|
||||||
|
<Icon
|
||||||
|
name="material-symbols:content-copy-outline-rounded"
|
||||||
|
:size="16"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</button>
|
||||||
</p>
|
</div>
|
||||||
<label class="label fs-14 mt-3">Mô tả<span class="has-text-danger"> *</span></label>
|
<label class="label fs-14 mt-3">Mô tả<span class="has-text-danger"> *</span></label>
|
||||||
<div class="field has-addons">
|
<div class="field has-addons">
|
||||||
<div class="control is-expanded">
|
<div class="control is-expanded">
|
||||||
<input
|
<input
|
||||||
class="input fs-14"
|
class="input fs-14 h-full"
|
||||||
type="text"
|
type="text"
|
||||||
@change="changeLabel($event.target.value)"
|
@change="changeLabel($event.target.value)"
|
||||||
v-model="label"
|
v-model="label"
|
||||||
@@ -287,39 +286,48 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<button
|
<button
|
||||||
class="button"
|
class="button h-full"
|
||||||
@click="editLabel()"
|
@click="editLabel()"
|
||||||
>
|
>
|
||||||
<SvgIcon v-bind="{ name: 'pen.svg', type: 'dark', size: 19 }"></SvgIcon>
|
<span class="icon">
|
||||||
|
<Icon
|
||||||
|
name="material-symbols:edit-outline-rounded"
|
||||||
|
:size="18"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p
|
<p
|
||||||
class="help is-danger"
|
|
||||||
v-if="errors.find((v) => v.name === 'label')"
|
v-if="errors.find((v) => v.name === 'label')"
|
||||||
|
class="help is-danger"
|
||||||
>
|
>
|
||||||
{{ errors.find((v) => v.name === "label").msg }}
|
{{ errors.find((v) => v.name === "label").msg }}
|
||||||
</p>
|
</p>
|
||||||
<div class="field mt-3">
|
<div class="field mt-3">
|
||||||
<label class="label fs-14">Kiểu dữ liệu<span class="has-text-danger"> * </span></label>
|
<label class="label fs-14">Kiểu dữ liệu<span class="has-text-danger"> * </span></label>
|
||||||
<div class="control fs-14">
|
<div class="control fs-14">
|
||||||
<span
|
<button
|
||||||
class="mr-4"
|
v-for="v in datatype"
|
||||||
v-for="(v, i) in datatype"
|
class="button is-white fs-14"
|
||||||
>
|
>
|
||||||
<span
|
<span class="icon">
|
||||||
class="icon-text"
|
<Icon
|
||||||
v-if="radioType === v"
|
:name="
|
||||||
>
|
radioType === v
|
||||||
<SvgIcon v-bind="{ name: 'radio-checked.svg', type: 'gray', size: 22 }"></SvgIcon>
|
? 'material-symbols:radio-button-checked-outline'
|
||||||
</span>
|
: 'material-symbols:radio-button-unchecked'
|
||||||
{{ v.name }}
|
"
|
||||||
|
:size="22"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
<span>{{ v.name }}</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="field is-horizontal"
|
|
||||||
v-if="currentField.format === 'number'"
|
v-if="currentField.format === 'number'"
|
||||||
|
class="field is-horizontal"
|
||||||
>
|
>
|
||||||
<div class="field-body">
|
<div class="field-body">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
@@ -334,7 +342,7 @@
|
|||||||
position: 'is-top-left',
|
position: 'is-top-left',
|
||||||
}"
|
}"
|
||||||
@option="selected('_account', $event)"
|
@option="selected('_account', $event)"
|
||||||
></SearchBox>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p
|
<p
|
||||||
class="help has-text-danger"
|
class="help has-text-danger"
|
||||||
@@ -361,27 +369,25 @@
|
|||||||
<div class="field-body">
|
<div class="field-body">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label fs-14">Định dạng nâng cao</label>
|
<label class="label fs-14">Định dạng nâng cao</label>
|
||||||
<p class="control fs-14">
|
<div class="control">
|
||||||
<span
|
<button
|
||||||
class="mr-4"
|
v-for="v in colorchoice.filter((v) => v.code !== 'condition')"
|
||||||
v-for="(v, i) in colorchoice.filter((v) => v.code !== 'condition')"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
class="icon-text"
|
|
||||||
@click="changeTemplate(v)"
|
@click="changeTemplate(v)"
|
||||||
|
class="button is-white fs-14"
|
||||||
>
|
>
|
||||||
<SvgIcon
|
<span class="icon">
|
||||||
v-bind="{
|
<Icon
|
||||||
name: `radio-${radioTemplate === v.code ? '' : 'un'}checked.svg`,
|
:name="
|
||||||
type: 'gray',
|
radioTemplate === v.code
|
||||||
size: 22,
|
? 'material-symbols:radio-button-checked-outline'
|
||||||
}"
|
: 'material-symbols:radio-button-unchecked'
|
||||||
>
|
"
|
||||||
</SvgIcon>
|
:size="22"
|
||||||
</a>
|
/>
|
||||||
{{ v.name }}
|
|
||||||
</span>
|
</span>
|
||||||
</p>
|
<span>{{ v.name }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -390,10 +396,10 @@
|
|||||||
v-if="radioTemplate === 'option'"
|
v-if="radioTemplate === 'option'"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="button is-primary is-small has-text-white"
|
class="button is-primary is-light fs-14"
|
||||||
@click="showSidebar()"
|
@click="showSidebar()"
|
||||||
>
|
>
|
||||||
<span class="fs-14">{{ `${currentField.template ? "Sửa" : "Tạo"} định dạng` }}</span>
|
{{ `${currentField.template ? "Sửa" : "Tạo"} định dạng` }}
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -414,7 +420,7 @@
|
|||||||
@label="changeLabel"
|
@label="changeLabel"
|
||||||
@updatefields="updateFields"
|
@updatefields="updateFields"
|
||||||
@close="close"
|
@close="close"
|
||||||
></Modal>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useStore } from "@/stores/index";
|
import { useStore } from "@/stores/index";
|
||||||
@@ -522,7 +528,6 @@ function doRemove() {
|
|||||||
copy.fields.splice(idx, 1);
|
copy.fields.splice(idx, 1);
|
||||||
copy.update = { fields: copy.fields };
|
copy.update = { fields: copy.fields };
|
||||||
store.commit(props.pagename, copy);
|
store.commit(props.pagename, copy);
|
||||||
emit("close");
|
|
||||||
}
|
}
|
||||||
function fieldList() {
|
function fieldList() {
|
||||||
showmodal.value = {
|
showmodal.value = {
|
||||||
@@ -538,7 +543,7 @@ function tableOption() {
|
|||||||
component: "datatable/TableSetting",
|
component: "datatable/TableSetting",
|
||||||
vbind: { pagename: props.pagename },
|
vbind: { pagename: props.pagename },
|
||||||
title: "Tùy chọn bảng",
|
title: "Tùy chọn bảng",
|
||||||
width: "40%",
|
width: "50%",
|
||||||
height: "400px",
|
height: "400px",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -556,9 +561,10 @@ const changeLabel = function (text) {
|
|||||||
function editLabel() {
|
function editLabel() {
|
||||||
showmodal.value = {
|
showmodal.value = {
|
||||||
component: "datatable/EditLabel",
|
component: "datatable/EditLabel",
|
||||||
|
title: "Điều chỉnh tiêu đề",
|
||||||
width: "500px",
|
width: "500px",
|
||||||
height: "300px",
|
height: "300px",
|
||||||
vbind: { label: label },
|
vbind: { label },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const changeTemplate = function (v) {
|
const changeTemplate = function (v) {
|
||||||
@@ -598,7 +604,7 @@ const saveSetting = function () {
|
|||||||
vbind: { pagename: props.pagename, classify: 4 },
|
vbind: { pagename: props.pagename, classify: 4 },
|
||||||
title: "Lưu thiết lập",
|
title: "Lưu thiết lập",
|
||||||
width: "500px",
|
width: "500px",
|
||||||
height: "400px",
|
height: "auto",
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
const showSidebar = function () {
|
const showSidebar = function () {
|
||||||
|
|||||||
@@ -4,33 +4,41 @@
|
|||||||
<div class="field-body">
|
<div class="field-body">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Đối tượng</label>
|
<label class="label">Đối tượng</label>
|
||||||
<p class="control fs-14">
|
<div class="control fs-14 is-flex is-gap-2">
|
||||||
<b-radio
|
<label
|
||||||
v-for="(v, i) in types"
|
v-for="(v, i) in types"
|
||||||
:key="i"
|
:key="i"
|
||||||
v-model="type"
|
class="radio"
|
||||||
:native-value="v"
|
|
||||||
@input="changeType(v)"
|
|
||||||
>
|
>
|
||||||
|
<input
|
||||||
|
v-model="type"
|
||||||
|
@input="changeType(v)"
|
||||||
|
type="radio"
|
||||||
|
name="type"
|
||||||
|
/>
|
||||||
{{ v.name }}
|
{{ v.name }}
|
||||||
</b-radio>
|
</label>
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Kích cỡ</label>
|
<label class="label">Kích cỡ</label>
|
||||||
<p class="control fs-14">
|
<div class="control fs-14 is-flex is-gap-2">
|
||||||
<b-radio
|
<label
|
||||||
v-for="(v, i) in sizes.filter((v) =>
|
v-for="(v, i) in sizes.filter((v) =>
|
||||||
type ? (type.code === 'tag' ? v.code !== 'is-small' : 1 > 0) : true,
|
type ? (type.code === 'tag' ? v.code !== 'is-small' : 1 > 0) : true,
|
||||||
)"
|
)"
|
||||||
:key="i"
|
:key="i"
|
||||||
v-model="size"
|
class="radio"
|
||||||
:native-value="v"
|
|
||||||
@input="changeType(v)"
|
|
||||||
>
|
>
|
||||||
|
<input
|
||||||
|
v-model="size"
|
||||||
|
@input="changeType(v)"
|
||||||
|
type="radio"
|
||||||
|
name="size"
|
||||||
|
/>
|
||||||
{{ v.name }}
|
{{ v.name }}
|
||||||
</b-radio>
|
</label>
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label
|
<label
|
||||||
@@ -38,20 +46,21 @@
|
|||||||
v-if="['tag'].find((v) => v === type.code)"
|
v-if="['tag'].find((v) => v === type.code)"
|
||||||
>Hình khối</label
|
>Hình khối</label
|
||||||
>
|
>
|
||||||
<p
|
<div class="control fs-14 is-flex is-gap-2">
|
||||||
class="control fs-14"
|
<label
|
||||||
v-if="['tag'].find((v) => v === type.code)"
|
|
||||||
>
|
|
||||||
<b-radio
|
|
||||||
v-for="(v, i) in shapes"
|
v-for="(v, i) in shapes"
|
||||||
:key="i"
|
:key="i"
|
||||||
v-model="shape"
|
class="radio"
|
||||||
:native-value="v"
|
|
||||||
@input="changeType(v)"
|
|
||||||
>
|
>
|
||||||
|
<input
|
||||||
|
v-model="shape"
|
||||||
|
@input="changeType(v)"
|
||||||
|
type="radio"
|
||||||
|
name="shape"
|
||||||
|
/>
|
||||||
{{ v.name }}
|
{{ v.name }}
|
||||||
</b-radio>
|
</label>
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -116,7 +125,7 @@
|
|||||||
:key="i"
|
:key="i"
|
||||||
@click="changeTab(v)"
|
@click="changeTab(v)"
|
||||||
>
|
>
|
||||||
<a class="fs-15">{{ v.name }}</a>
|
<a class="">{{ v.name }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -346,68 +355,77 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="tab.code === 'template'">
|
<template v-else-if="tab.code === 'template'">
|
||||||
<p class="mb-3">
|
<div class="buttons mb-3">
|
||||||
<a
|
<button
|
||||||
@click="copyContent()"
|
@click="copyContent()"
|
||||||
class="mr-6"
|
class="button is-primary is-light fs-14"
|
||||||
>
|
>
|
||||||
<span class="icon-text">
|
<span class="icon">
|
||||||
<SvgIcon
|
<Icon
|
||||||
class="mr-2"
|
name="material-symbols:content-copy-outline-rounded"
|
||||||
v-bind="{ name: 'copy.svg', type: 'primary', siz: 18 }"
|
:size="18"
|
||||||
></SvgIcon>
|
/>
|
||||||
<span class="fs-16">Copy</span>
|
|
||||||
</span>
|
</span>
|
||||||
</a>
|
<span>Copy</span>
|
||||||
<a
|
</button>
|
||||||
|
<button
|
||||||
@click="paste()"
|
@click="paste()"
|
||||||
class="mr-6"
|
class="button is-primary is-light fs-14"
|
||||||
>
|
>
|
||||||
<span class="icon-text">
|
<span class="icon">
|
||||||
<SvgIcon
|
<Icon
|
||||||
class="mr-2"
|
name="material-symbols:content-paste-rounded"
|
||||||
v-bind="{ name: 'pen1.svg', type: 'primary', siz: 18 }"
|
:size="18"
|
||||||
></SvgIcon>
|
/>
|
||||||
<span class="fs-16">Paste</span>
|
|
||||||
</span>
|
</span>
|
||||||
</a>
|
<span>Paste</span>
|
||||||
</p>
|
</button>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<textarea
|
<textarea
|
||||||
class="textarea fs-14"
|
class="textarea fs-13"
|
||||||
rows="8"
|
style="font-family: monospace"
|
||||||
|
rows="4"
|
||||||
v-model="text"
|
v-model="text"
|
||||||
@dblclick="doCheck"
|
@dblclick="doCheck"
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
<p class="mt-5">
|
<p class="mt-5">
|
||||||
<span class="icon-text fsb-18">
|
<span class="icon-text">
|
||||||
Replace
|
<span class="fs-17 font-semibold">Replace</span>
|
||||||
<SvgIcon v-bind="{ name: 'right.svg', type: 'dark', size: 22 }"></SvgIcon>
|
<span class="icon">
|
||||||
|
<Icon
|
||||||
|
name="material-symbols:arrow-forward-ios-rounded"
|
||||||
|
:size="18"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<div class="field is-grouped mt-4">
|
<div class="field is-grouped mt-4">
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<p class="fsb-14 mb-1">Đoạn text</p>
|
<label class="label">Đoạn text</label>
|
||||||
<input
|
<input
|
||||||
class="input"
|
class="input"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder=""
|
|
||||||
v-model="source"
|
v-model="source"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<p class="fsb-14 mb-1">Thay bằng</p>
|
<label class="label">Thay bằng</label>
|
||||||
<input
|
<input
|
||||||
class="input"
|
class="input"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder=""
|
|
||||||
v-model="target"
|
v-model="target"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="control pl-5">
|
<div class="control">
|
||||||
|
<label
|
||||||
|
class="label"
|
||||||
|
style="opacity: 0"
|
||||||
|
>Hidden</label
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
class="button is-primary is-outlined mt-5"
|
class="button is-primary is-light"
|
||||||
@click="replace()"
|
@click="replace()"
|
||||||
>
|
>
|
||||||
Replace
|
Replace
|
||||||
|
|||||||
@@ -1,20 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="field is-grouped is-grouped-multiline pl-2"
|
class="field is-grouped is-grouped-multiline is-gap-4 px-2"
|
||||||
v-if="filters ? filters.length > 0 : false"
|
v-if="filters ? filters.length > 0 : false"
|
||||||
>
|
>
|
||||||
<div class="control mr-5">
|
<div class="control">
|
||||||
<a
|
<a
|
||||||
class="button is-primary is-small has-text-white has-text-weight-bold"
|
class="button is-primary is-light"
|
||||||
@click="updateData({ filters: [] })"
|
@click="updateData({ filters: [] })"
|
||||||
>
|
>
|
||||||
<span class="fs-14">Xóa lọc</span>
|
<span class="fs-14">Xóa lọc</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="control pr-2 mr-5">
|
<div class="control">
|
||||||
<span class="icon-text">
|
<span class="icon-text">
|
||||||
<SvgIcon v-bind="{ name: 'sigma.svg', type: 'primary', size: 20 }"></SvgIcon>
|
<span class="icon">
|
||||||
<span class="fsb-18 has-text-primary">{{ totalRows }}</span>
|
<Icon
|
||||||
|
name="mdi:sigma"
|
||||||
|
:size="20"
|
||||||
|
class="has-text-primary"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span class="fs-16 font-semibold has-text-primary">{{ totalRows }}</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -24,16 +30,16 @@
|
|||||||
>
|
>
|
||||||
<div class="tags has-addons is-marginless">
|
<div class="tags has-addons is-marginless">
|
||||||
<a
|
<a
|
||||||
class="tag is-primary has-text-white is-marginless"
|
class="tag is-primary is-light is-marginless"
|
||||||
@click="showCondition(v)"
|
@click="showCondition(v)"
|
||||||
>{{ v.label.indexOf(">") >= 0 ? $stripHtml(v.label, 30) : v.label }}</a
|
>{{ v.label.indexOf(">") >= 0 ? $stripHtml(v.label, 30) : v.label }}</a
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
class="tag is-delete is-marginless has-text-black-bis"
|
class="tag is-delete is-marginless"
|
||||||
@click="removeFilter(i)"
|
@click="removeFilter(i)"
|
||||||
></a>
|
></a>
|
||||||
</div>
|
</div>
|
||||||
<span class="help has-text-black-bis">
|
<span class="help">
|
||||||
{{
|
{{
|
||||||
v.sort
|
v.sort
|
||||||
? v.sort
|
? v.sort
|
||||||
@@ -59,14 +65,13 @@
|
|||||||
v-for="(field, i) in displayFields"
|
v-for="(field, i) in displayFields"
|
||||||
:key="i"
|
:key="i"
|
||||||
:style="field.headerStyle"
|
:style="field.headerStyle"
|
||||||
>
|
class="is-clickable header"
|
||||||
<div
|
|
||||||
@click="showField(field)"
|
@click="showField(field)"
|
||||||
:style="field.dropStyle"
|
|
||||||
>
|
>
|
||||||
|
<div :style="field.dropStyle">
|
||||||
<a
|
<a
|
||||||
v-if="field.label.indexOf('<') < 0"
|
v-if="field.label.indexOf('<') < 0"
|
||||||
class="has-text-white font-semibold"
|
class="font-semibold"
|
||||||
>{{ field.label }}</a
|
>{{ field.label }}</a
|
||||||
>
|
>
|
||||||
<a v-else>
|
<a v-else>
|
||||||
@@ -160,13 +165,12 @@ var currentPage = 1;
|
|||||||
var displayFields = ref([]);
|
var displayFields = ref([]);
|
||||||
var displayData = [];
|
var displayData = [];
|
||||||
var pagedata = store[props.pagename];
|
var pagedata = store[props.pagename];
|
||||||
console.log("props.pagename", props.pagename);
|
var tablesetting = $copy(pagedata.tablesetting || store.tablesetting);
|
||||||
console.log("store", toRaw(store));
|
if (!Array.isArray(tablesetting)) {
|
||||||
console.log("store[props.pagename]", toRaw(store[props.pagename]));
|
tablesetting = Object.values(tablesetting);
|
||||||
console.log("pagedata.tablesetting", toRaw(pagedata.tablesetting)); // table-font-size is 13
|
}
|
||||||
console.log("store.tablesetting", toRaw(store.tablesetting)); // table-font-size is 12
|
// var tablesetting = $copy(store.tablesetting);
|
||||||
// var tablesetting = $copy(pagedata.tablesetting || store.tablesetting);
|
// const tablesettingObj = Object.fromEntries(tablesetting.map((v) => [v.code, v]));
|
||||||
var tablesetting = $copy(store.tablesetting);
|
|
||||||
var perPage = Number($find(tablesetting, { code: "per-page" }, "detail")) || 20;
|
var perPage = Number($find(tablesetting, { code: "per-page" }, "detail")) || 20;
|
||||||
var filters = $copy(pagedata.filters || []);
|
var filters = $copy(pagedata.filters || []);
|
||||||
var currentField;
|
var currentField;
|
||||||
@@ -551,7 +555,10 @@ setTimeout(() => updateShow(), 200);
|
|||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
:deep(.table tbody tr:hover td, .table tbody tr:hover th) {
|
:deep(.table tbody tr:hover td, .table tbody tr:hover th) {
|
||||||
background-color: hsl(0, 0%, 78%);
|
--bulma-table-row-hover-background-color: var(--bulma-scheme-main-ter);
|
||||||
color: rgb(0, 0, 0);
|
background-color: var(--bulma-table-row-hover-background-color);
|
||||||
|
}
|
||||||
|
.header:hover a {
|
||||||
|
opacity: 0.75;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<p class="fsb-20 mb-5">Điều chỉnh tiêu đề</p>
|
|
||||||
<div
|
<div
|
||||||
v-for="(v, i) in arr"
|
v-for="(v, i) in arr"
|
||||||
:key="i"
|
:key="i"
|
||||||
:class="i > 0 ? 'mt-4' : null"
|
:class="i > 0 && 'mt-4'"
|
||||||
>
|
>
|
||||||
<p class="fsb-14">Dòng thứ {{ i + 1 }}<span class="has-text-danger"> *</span></p>
|
<p class="font-semibold">Dòng thứ {{ i + 1 }}<span class="has-text-danger"> *</span></p>
|
||||||
<div class="field has-addons mt-1">
|
<div class="field has-addons mt-1">
|
||||||
<div class="control is-expanded">
|
<div class="control is-expanded">
|
||||||
<input
|
<input
|
||||||
@@ -16,23 +15,31 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<a
|
<button
|
||||||
class="button px-2 is-primary"
|
class="button is-success is-light"
|
||||||
@click="add()"
|
@click="add()"
|
||||||
>
|
>
|
||||||
<span> <SvgIcon v-bind="{ name: 'add1.png', type: 'white', size: 17 }"></SvgIcon></span>
|
<span class="icon">
|
||||||
</a>
|
<Icon
|
||||||
|
name="material-symbols:add-rounded"
|
||||||
|
:size="20"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="control"
|
class="control"
|
||||||
@click="remove(i)"
|
@click="remove(i)"
|
||||||
v-if="i > 0"
|
v-if="i > 0"
|
||||||
>
|
>
|
||||||
<a class="button px-2 is-dark">
|
<button class="button is-danger is-light">
|
||||||
<span>
|
<span class="icon">
|
||||||
<SvgIcon v-bind="{ name: 'bin.svg', type: 'white', size: 17 }"></SvgIcon>
|
<Icon
|
||||||
|
name="material-symbols:delete-outline-rounded"
|
||||||
|
:size="20"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p
|
<p
|
||||||
@@ -50,10 +57,10 @@
|
|||||||
Cập nhật
|
Cập nhật
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="button is-dark"
|
class="button is-white"
|
||||||
@click="$emit('close')"
|
@click="$emit('close')"
|
||||||
>
|
>
|
||||||
Hủy bỏ
|
Hủy
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -72,7 +79,7 @@ export default {
|
|||||||
if (!this.$empty(v)) {
|
if (!this.$empty(v)) {
|
||||||
let label = v + "</p>";
|
let label = v + "</p>";
|
||||||
label = this.$stripHtml(label);
|
label = this.$stripHtml(label);
|
||||||
this.arr.push({ label: label });
|
this.arr.push({ label });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -27,45 +27,56 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field is-narrow">
|
<div class="field is-narrow has-addons">
|
||||||
<p class="control">
|
<p class="control">
|
||||||
<a @click="addAttr()">
|
<button
|
||||||
<SvgIcon v-bind="{ name: 'add1.png', type: 'gray', size: 18 }"></SvgIcon>
|
class="button is-primary is-light"
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
class="ml-2"
|
|
||||||
@click="remove(i)"
|
|
||||||
>
|
|
||||||
<SvgIcon v-bind="{ name: 'bin1.svg', type: 'gray', size: 18 }"></SvgIcon>
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
class="ml-2"
|
|
||||||
@click="jsonData(v, i)"
|
@click="jsonData(v, i)"
|
||||||
>
|
>
|
||||||
<SvgIcon v-bind="{ name: 'apps.svg', type: 'gray', size: 18 }"></SvgIcon>
|
<span class="icon">
|
||||||
</a>
|
<Icon
|
||||||
|
name="material-symbols:app-registration-rounded"
|
||||||
|
:size="20"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
<p class="control">
|
||||||
|
<button
|
||||||
|
class="button is-primary is-light"
|
||||||
|
@click="remove(i)"
|
||||||
|
>
|
||||||
|
<span class="icon">
|
||||||
|
<Icon
|
||||||
|
name="material-symbols:delete-outline-rounded"
|
||||||
|
:size="20"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div
|
|
||||||
class="mb-6"
|
|
||||||
v-else
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
class="button is-primary has-text-white"
|
class="button is-success is-light"
|
||||||
@click="addAttr()"
|
@click="addAttr()"
|
||||||
>
|
>
|
||||||
Thêm thuộc tính
|
<span class="icon">
|
||||||
|
<Icon
|
||||||
|
name="material-symbols:add-rounded"
|
||||||
|
:size="20"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span>Thêm thuộc tính</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
<div class="mt-2">
|
||||||
<div class="buttons mt-5">
|
<button
|
||||||
<a
|
class="button is-primary"
|
||||||
class="button is-primary has-text-white"
|
|
||||||
@click="update()"
|
@click="update()"
|
||||||
>Cập nhật</a
|
|
||||||
>
|
>
|
||||||
|
Cập nhật
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<Modal
|
<Modal
|
||||||
@close="comp = undefined"
|
@close="comp = undefined"
|
||||||
|
|||||||
@@ -1,55 +1,61 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<!-- v-if="currentsetting ? currentsetting.user === login.id : false" -->
|
||||||
<div
|
<div
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
v-if="currentsetting ? currentsetting.user === login.id : false"
|
v-if="currentsetting"
|
||||||
>
|
>
|
||||||
<p class="fs-16 has-text-findata">
|
<p>
|
||||||
Đang mở: <b>{{ $stripHtml(currentsetting.name, 40) }}</b>
|
Đang mở: <b>{{ $stripHtml(currentsetting.name, 40) }}</b>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label fs-14">Chọn chế độ lưu <span class="has-text-danger"> * </span></label>
|
<label class="label">Chọn chế độ lưu <span class="has-text-danger"> * </span></label>
|
||||||
<div class="control is-expanded fs-14">
|
<div class="control is-expanded fs-14">
|
||||||
<a
|
<button
|
||||||
class="mr-5"
|
class="button is-white has-text-inherit"
|
||||||
v-if="isOverwrite()"
|
v-if="isOverwrite()"
|
||||||
@click="changeType('overwrite')"
|
@click="changeType('overwrite')"
|
||||||
>
|
>
|
||||||
<span class="icon-text">
|
<span class="icon">
|
||||||
<SvgIcon
|
<Icon
|
||||||
v-bind="{
|
:name="
|
||||||
name: radioSave === 'overwrite' ? 'radio-checked.svg' : 'radio-unchecked.svg',
|
radioSave === 'overwrite'
|
||||||
type: 'gray',
|
? 'material-symbols:radio-button-checked-outline'
|
||||||
size: 22,
|
: 'material-symbols:radio-button-unchecked'
|
||||||
}"
|
"
|
||||||
></SvgIcon>
|
:size="22"
|
||||||
Ghi đè
|
/>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
<span>Ghi đè</span>
|
||||||
<a @click="changeType('new')">
|
</button>
|
||||||
<span class="icon-text">
|
<button
|
||||||
<SvgIcon
|
class="button is-white"
|
||||||
v-bind="{
|
@click="changeType('new')"
|
||||||
name: radioSave === 'new' ? 'radio-checked.svg' : 'radio-unchecked.svg',
|
>
|
||||||
type: 'gray',
|
<span class="icon">
|
||||||
size: 22,
|
<Icon
|
||||||
}"
|
:name="
|
||||||
></SvgIcon>
|
radioSave === 'new'
|
||||||
Tạo mới
|
? 'material-symbols:radio-button-checked-outline'
|
||||||
|
: 'material-symbols:radio-button-unchecked'
|
||||||
|
"
|
||||||
|
:size="22"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
<span>Tạo mới</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="radioSave === 'new'">
|
<template v-if="radioSave === 'new'">
|
||||||
<div class="field mt-4 px-0 mx-0">
|
<div class="field">
|
||||||
<label class="label fs-14">Tên thiết lập <span class="has-text-danger"> * </span></label>
|
<label class="label">Tên thiết lập <span class="has-text-danger"> * </span></label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
|
<!-- ref="name" -->
|
||||||
<input
|
<input
|
||||||
class="input"
|
class="input"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder=""
|
placeholder=""
|
||||||
v-model="name"
|
v-model="name"
|
||||||
ref="name"
|
|
||||||
v-on:keyup.enter="saveSetting"
|
v-on:keyup.enter="saveSetting"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -60,12 +66,12 @@
|
|||||||
{{ errors.find((v) => v.name === "name").msg }}
|
{{ errors.find((v) => v.name === "name").msg }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field mt-4 px-0 mx-0">
|
<div class="field">
|
||||||
<label class="label fs-14"> Mô tả </label>
|
<label class="label"> Mô tả </label>
|
||||||
<p class="control is-expanded">
|
<p class="control is-expanded">
|
||||||
<textarea
|
<textarea
|
||||||
class="textarea"
|
class="textarea"
|
||||||
rows="4"
|
rows="3"
|
||||||
v-model="note"
|
v-model="note"
|
||||||
></textarea>
|
></textarea>
|
||||||
</p>
|
</p>
|
||||||
@@ -93,11 +99,12 @@
|
|||||||
{{ status ? "Lưu thiết lập thành công." : "Lỗi. Lưu thiết lập thất bại." }}
|
{{ status ? "Lưu thiết lập thành công." : "Lỗi. Lưu thiết lập thất bại." }}
|
||||||
</label>
|
</label>
|
||||||
<p class="control is-expanded">
|
<p class="control is-expanded">
|
||||||
<a
|
<button
|
||||||
class="button is-primary has-text-white"
|
:class="['button is-primary', isLoading && 'is-loading']"
|
||||||
@click="saveSetting()"
|
@click="saveSetting()"
|
||||||
>Lưu lại</a
|
|
||||||
>
|
>
|
||||||
|
Lưu lại
|
||||||
|
</button>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -106,28 +113,30 @@ import { ref } from "vue";
|
|||||||
import { useStore } from "@/stores/index";
|
import { useStore } from "@/stores/index";
|
||||||
const emit = defineEmits([]);
|
const emit = defineEmits([]);
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
var props = defineProps({
|
const props = defineProps({
|
||||||
pagename: String,
|
pagename: String,
|
||||||
classify: String,
|
classify: String,
|
||||||
option: String,
|
option: String,
|
||||||
data: Object,
|
data: Object,
|
||||||
focus: Boolean,
|
focus: Boolean,
|
||||||
});
|
});
|
||||||
const { $empty, $copy, $filter, $stripHtml, $updateapi, $insertapi, $findIndex, $snackbar } = useNuxtApp();
|
const { $empty, $copy, $stripHtml, $updateapi, $insertapi, $findIndex, $snackbar } = useNuxtApp();
|
||||||
var pagename = props.pagename;
|
const radioOption = ref();
|
||||||
var radioOption = ref();
|
|
||||||
var login = { id: 1 };
|
var login = { id: 1 };
|
||||||
var errors = [];
|
const errors = ref([]);
|
||||||
var radioType = undefined;
|
const radioType = ref();
|
||||||
var radioDefault = 0;
|
const radioDefault = 0;
|
||||||
var radioSave = ref("new");
|
const radioSave = ref("overwrite");
|
||||||
var note = undefined;
|
const name = ref();
|
||||||
var status = undefined;
|
const note = ref();
|
||||||
var name = undefined;
|
const status = undefined;
|
||||||
var currentsetting = undefined;
|
var currentsetting = undefined;
|
||||||
|
var pagename = props.pagename;
|
||||||
var pagedata = store[props.pagename];
|
var pagedata = store[props.pagename];
|
||||||
|
const isLoading = ref(false);
|
||||||
|
|
||||||
async function saveSetting() {
|
async function saveSetting() {
|
||||||
errors = [];
|
errors.value = [];
|
||||||
let detail = pagename ? { fields: pagedata.fields } : {};
|
let detail = pagename ? { fields: pagedata.fields } : {};
|
||||||
if (pagename) {
|
if (pagename) {
|
||||||
let element = pagedata.tablesetting || {};
|
let element = pagedata.tablesetting || {};
|
||||||
@@ -139,19 +148,21 @@ async function saveSetting() {
|
|||||||
if (props.option) detail.option = props.option;
|
if (props.option) detail.option = props.option;
|
||||||
if (props.data) detail.data = props.data;
|
if (props.data) detail.data = props.data;
|
||||||
let data = {
|
let data = {
|
||||||
user: login.id,
|
// user: login.id,
|
||||||
name: name,
|
user: undefined,
|
||||||
detail: detail,
|
name: name.value,
|
||||||
note: note,
|
detail,
|
||||||
type: radioType.id,
|
note,
|
||||||
|
type: radioType.value.id,
|
||||||
classify: props.classify ? props.classify : store.settingclass.find((v) => v.code === "data-field").id,
|
classify: props.classify ? props.classify : store.settingclass.find((v) => v.code === "data-field").id,
|
||||||
default: radioDefault,
|
default: radioDefault,
|
||||||
update_time: new Date(),
|
update_time: new Date(),
|
||||||
};
|
};
|
||||||
let result;
|
let result;
|
||||||
|
isLoading.value = true;
|
||||||
if (radioSave.value === "new") {
|
if (radioSave.value === "new") {
|
||||||
if ($empty(name)) {
|
if ($empty(name.value)) {
|
||||||
return errors.push({
|
return errors.value.push({
|
||||||
name: "name",
|
name: "name",
|
||||||
msg: "Tên thiết lập không được bỏ trống",
|
msg: "Tên thiết lập không được bỏ trống",
|
||||||
});
|
});
|
||||||
@@ -163,6 +174,7 @@ async function saveSetting() {
|
|||||||
copy.update_time = new Date();
|
copy.update_time = new Date();
|
||||||
result = await $updateapi("usersetting", copy);
|
result = await $updateapi("usersetting", copy);
|
||||||
}
|
}
|
||||||
|
isLoading.value = false;
|
||||||
if (radioSave.value === "new") {
|
if (radioSave.value === "new") {
|
||||||
emit("modalevent", { name: "opensetting", data: result });
|
emit("modalevent", { name: "opensetting", data: result });
|
||||||
} else {
|
} else {
|
||||||
@@ -187,11 +199,12 @@ function changeOption(v) {
|
|||||||
radioOption.value = v.code;
|
radioOption.value = v.code;
|
||||||
}
|
}
|
||||||
function initData() {
|
function initData() {
|
||||||
radioType = store.settingtype.find((v) => v.code === "private");
|
radioType.value = store.settingtype.find((v) => v.code === "private");
|
||||||
if (props.pagename) currentsetting = $copy(pagedata.setting ? pagedata.setting : undefined);
|
if (props.pagename) currentsetting = $copy(pagedata.setting ? pagedata.setting : undefined);
|
||||||
if (!currentsetting) radioSave.value = "new";
|
// disable temp: for now, radioSave is always 'overwrite'
|
||||||
|
/* if (!currentsetting) radioSave.value = "new";
|
||||||
else if (currentsetting.user !== login.id) radioSave.value = "new";
|
else if (currentsetting.user !== login.id) radioSave.value = "new";
|
||||||
else radioSave.value = "overwrite";
|
else radioSave.value = "overwrite"; */
|
||||||
}
|
}
|
||||||
initData();
|
initData();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -2,10 +2,12 @@
|
|||||||
<div class="tabs is-boxed">
|
<div class="tabs is-boxed">
|
||||||
<ul>
|
<ul>
|
||||||
<li
|
<li
|
||||||
:class="selectType.code === v.code ? 'is-active fs-16' : 'fs-16'"
|
|
||||||
v-for="v in fieldType"
|
v-for="v in fieldType"
|
||||||
|
:class="selectType.code === v.code && 'is-active'"
|
||||||
>
|
>
|
||||||
<a @click="selectType = v"
|
<a
|
||||||
|
class="has-text-inherit"
|
||||||
|
@click="selectType = v"
|
||||||
><span>{{ v.name }}</span></a
|
><span>{{ v.name }}</span></a
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
@@ -148,7 +150,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="field px-0 mx-0">
|
<div class="field">
|
||||||
<label class="label">Tên trường <span class="has-text-danger"> * </span> </label>
|
<label class="label">Tên trường <span class="has-text-danger"> * </span> </label>
|
||||||
<p class="control">
|
<p class="control">
|
||||||
<input
|
<input
|
||||||
@@ -166,13 +168,13 @@
|
|||||||
{{ errors.find((v) => v.name === "name").message }}
|
{{ errors.find((v) => v.name === "name").message }}
|
||||||
</p>
|
</p>
|
||||||
<p
|
<p
|
||||||
class="help has-text-primary"
|
class="help has-text-grey"
|
||||||
v-else
|
v-else
|
||||||
>
|
>
|
||||||
Tên trường do hệ thống tự sinh.
|
Tên trường do hệ thống tự sinh.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-5">
|
<div class="field">
|
||||||
<label class="label">Mô tả<span class="has-text-danger"> *</span></label>
|
<label class="label">Mô tả<span class="has-text-danger"> *</span></label>
|
||||||
<div class="field has-addons">
|
<div class="field has-addons">
|
||||||
<div class="control is-expanded">
|
<div class="control is-expanded">
|
||||||
@@ -187,7 +189,12 @@
|
|||||||
class="button"
|
class="button"
|
||||||
@click="editLabel()"
|
@click="editLabel()"
|
||||||
>
|
>
|
||||||
<span><SvgIcon v-bind="{ name: 'pen.svg', type: 'dark', size: 17 }"></SvgIcon></span>
|
<span class="icon">
|
||||||
|
<Icon
|
||||||
|
name="material-symbols:edit-outline-rounded"
|
||||||
|
:size="18"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -199,53 +206,47 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="field mt-5"
|
class="field"
|
||||||
v-if="selectType.code === 'empty'"
|
v-if="selectType.code === 'empty'"
|
||||||
>
|
>
|
||||||
<label class="label"
|
<label class="label"
|
||||||
>Kiểu dữ liệu
|
>Kiểu dữ liệu
|
||||||
<span class="has-text-danger"> * </span>
|
<span class="has-text-danger"> * </span>
|
||||||
</label>
|
</label>
|
||||||
<div class="control fs-14">
|
<div class="control">
|
||||||
<span
|
<button
|
||||||
class="mr-4"
|
|
||||||
v-for="(v, i) in datatype"
|
v-for="(v, i) in datatype"
|
||||||
>
|
class="button is-white fs-14"
|
||||||
<a
|
|
||||||
class="icon-text"
|
|
||||||
@click="changeType(v)"
|
@click="changeType(v)"
|
||||||
>
|
>
|
||||||
<SvgIcon
|
<span class="icon">
|
||||||
v-bind="{
|
<Icon
|
||||||
name: `radio-${radioType.code === v.code ? '' : 'un'}checked.svg`,
|
:name="
|
||||||
type: 'gray',
|
radioType.code === v.code
|
||||||
size: 22,
|
? 'material-symbols:radio-button-checked-outline'
|
||||||
}"
|
: 'material-symbols:radio-button-unchecked'
|
||||||
></SvgIcon>
|
"
|
||||||
</a>
|
:size="22"
|
||||||
{{ v.name }}
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
<span>{{ v.name }}</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field mt-5">
|
<button
|
||||||
<p class="control">
|
class="button is-primary"
|
||||||
<a
|
|
||||||
class="button is-primary has-text-white"
|
|
||||||
@click="selectType.code === 'formula' ? createField() : createEmptyField()"
|
@click="selectType.code === 'formula' ? createField() : createEmptyField()"
|
||||||
>Tạo cột</a
|
|
||||||
>
|
>
|
||||||
</p>
|
Tạo cột
|
||||||
</div>
|
</button>
|
||||||
<Modal
|
<Modal
|
||||||
v-bind="showmodal"
|
v-bind="showmodal"
|
||||||
v-if="showmodal"
|
|
||||||
@label="changeLabel"
|
@label="changeLabel"
|
||||||
@close="close"
|
@close="close"
|
||||||
></Modal>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useStore } from "@/stores/index";
|
import { useStore } from "@/stores/index";
|
||||||
import ScrollBox from "~/components/datatable/ScrollBox";
|
|
||||||
const emit = defineEmits(["modalevent"]);
|
const emit = defineEmits(["modalevent"]);
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const { $id, $copy, $clone, $empty, $stripHtml, $createField, $calc, $isNumber } = useNuxtApp();
|
const { $id, $copy, $clone, $empty, $stripHtml, $createField, $calc, $isNumber } = useNuxtApp();
|
||||||
@@ -256,7 +257,7 @@ var props = defineProps({
|
|||||||
filterData: Object,
|
filterData: Object,
|
||||||
width: String,
|
width: String,
|
||||||
});
|
});
|
||||||
const moneyunit = store.moneyunit;
|
const moneyunit = store.moneyunit || [];
|
||||||
const datatype = store.datatype;
|
const datatype = store.datatype;
|
||||||
var showmodal = ref();
|
var showmodal = ref();
|
||||||
var pagedata = store[props.pagename];
|
var pagedata = store[props.pagename];
|
||||||
@@ -265,16 +266,15 @@ var data = [];
|
|||||||
var current = 1;
|
var current = 1;
|
||||||
var filterData = [];
|
var filterData = [];
|
||||||
var loading = false;
|
var loading = false;
|
||||||
var fieldType = [
|
const fieldType = [
|
||||||
{ code: "formula", name: "Tạo công thức" },
|
{ code: "formula", name: "Tạo công thức" },
|
||||||
{ code: "empty", name: "Tạo cột rỗng" },
|
{ code: "empty", name: "Tạo cột rỗng" },
|
||||||
];
|
];
|
||||||
var errors = [];
|
|
||||||
var tags = [];
|
var tags = [];
|
||||||
var formula = undefined;
|
var formula = undefined;
|
||||||
var name = `f${$id().toLocaleLowerCase()}`;
|
var name = `f${$id().toLocaleLowerCase()}`;
|
||||||
var label = undefined;
|
var label = undefined;
|
||||||
var errors = [];
|
const errors = ref([]);
|
||||||
var selectType = fieldType.find((v) => v.code === "empty");
|
var selectType = fieldType.find((v) => v.code === "empty");
|
||||||
var radioType = ref(datatype.find((v) => v.code === "string"));
|
var radioType = ref(datatype.find((v) => v.code === "string"));
|
||||||
var fields = [];
|
var fields = [];
|
||||||
@@ -362,25 +362,25 @@ function checkFunc() {
|
|||||||
return error ? "error" : content;
|
return error ? "error" : content;
|
||||||
}
|
}
|
||||||
function checkValid() {
|
function checkValid() {
|
||||||
errors = [];
|
errors.value = [];
|
||||||
if (tags.length === 0 && choice === "column") {
|
if (tags.length === 0 && choice === "column") {
|
||||||
errors.push({
|
errors.value.push({
|
||||||
name: "tags",
|
name: "tags",
|
||||||
message: "Chưa chọn trường xây dựng công thức.",
|
message: "Chưa chọn trường xây dựng công thức.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!$empty(formula) ? $empty(formula.trim()) : true) {
|
if (!$empty(formula) ? $empty(formula.trim()) : true) {
|
||||||
errors.push({ name: "formula", message: "Công thức không được bỏ trống." });
|
errors.value.push({ name: "formula", message: "Công thức không được bỏ trống." });
|
||||||
}
|
}
|
||||||
if (!$empty(label) ? $empty(label.trim()) : true)
|
if (!$empty(label) ? $empty(label.trim()) : true)
|
||||||
errors.push({ name: "label", message: "Mô tả không được bỏ trống." });
|
errors.value.push({ name: "label", message: "Mô tả không được bỏ trống." });
|
||||||
else if (pagedata.fields.find((v) => v.label.toLowerCase() === label.toLowerCase())) {
|
else if (pagedata.fields.find((v) => v.label.toLowerCase() === label.toLowerCase())) {
|
||||||
errors.push({
|
errors.value.push({
|
||||||
name: "label",
|
name: "label",
|
||||||
message: "Mô tả bị trùng. Hãy đặt mô tả khác.",
|
message: "Mô tả bị trùng. Hãy đặt mô tả khác.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (errors.length > 0) return false;
|
if (errors.value.length > 0) return false;
|
||||||
//check formula in case use column
|
//check formula in case use column
|
||||||
if (choice === "column") {
|
if (choice === "column") {
|
||||||
let val = $copy(formula);
|
let val = $copy(formula);
|
||||||
@@ -391,20 +391,20 @@ function checkValid() {
|
|||||||
try {
|
try {
|
||||||
let value = $calc(val);
|
let value = $calc(val);
|
||||||
if (isNaN(value) || value === Number.POSITIVE_INFINITY || value === Number.NEGATIVE_INFINITY) {
|
if (isNaN(value) || value === Number.POSITIVE_INFINITY || value === Number.NEGATIVE_INFINITY) {
|
||||||
errors.push({ name: "formula", message: "Công thức không hợp lệ" });
|
errors.value.push({ name: "formula", message: "Công thức không hợp lệ" });
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
errors.push({ name: "formula", message: "Công thức không hợp lệ" });
|
errors.value.push({ name: "formula", message: "Công thức không hợp lệ" });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (checkFunc() === "error")
|
if (checkFunc() === "error")
|
||||||
errors.push({
|
errors.value.push({
|
||||||
name: "formula",
|
name: "formula",
|
||||||
message: `Hàm ${func.toUpperCase()} không hợp lệ`,
|
message: `Hàm ${func.toUpperCase()} không hợp lệ`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return errors.length > 0 ? false : true;
|
return errors.value.length > 0 ? false : true;
|
||||||
}
|
}
|
||||||
function createField() {
|
function createField() {
|
||||||
if (!checkValid()) return;
|
if (!checkValid()) return;
|
||||||
@@ -429,23 +429,26 @@ function createField() {
|
|||||||
emit("close");
|
emit("close");
|
||||||
}
|
}
|
||||||
function createEmptyField() {
|
function createEmptyField() {
|
||||||
errors = [];
|
console.log("createEmptyField");
|
||||||
if (!$empty(name) ? $empty(name.trim()) : true) errors.push({ name: "name", message: "Tên không được bỏ trống." });
|
errors.value = [];
|
||||||
|
if (!$empty(name) ? $empty(name.trim()) : true)
|
||||||
|
errors.value.push({ name: "name", message: "Tên không được bỏ trống." });
|
||||||
else if (pagedata.fields.find((v) => v.name.toLowerCase() === name.toLowerCase())) {
|
else if (pagedata.fields.find((v) => v.name.toLowerCase() === name.toLowerCase())) {
|
||||||
errors.push({
|
errors.value.push({
|
||||||
name: "name",
|
name: "name",
|
||||||
message: "Tên trường bị trùng. Hãy đặt tên khác.",
|
message: "Tên trường bị trùng. Hãy đặt tên khác.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!$empty(label) ? $empty(label.trim()) : true)
|
if (!$empty(label) ? $empty(label.trim()) : true)
|
||||||
errors.push({ name: "label", message: "Mô tả không được bỏ trống." });
|
errors.value.push({ name: "label", message: "Mô tả không được bỏ trống." });
|
||||||
else if (pagedata.fields.find((v) => v.label.toLowerCase() === label.toLowerCase())) {
|
else if (pagedata.fields.find((v) => v.label.toLowerCase() === label.toLowerCase())) {
|
||||||
errors.push({
|
errors.value.push({
|
||||||
name: "label",
|
name: "label",
|
||||||
message: "Mô tả bị trùng. Hãy đặt mô tả khác.",
|
message: "Mô tả bị trùng. Hãy đặt mô tả khác.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (errors.length > 0) return;
|
console.log("errors", errors);
|
||||||
|
if (errors.value.length > 0) return;
|
||||||
let field = $createField(name.trim(), label.trim(), radioType.value.code, true);
|
let field = $createField(name.trim(), label.trim(), radioType.value.code, true);
|
||||||
if (selectType.code === "chart") field = createChartField();
|
if (selectType.code === "chart") field = createChartField();
|
||||||
let copy = $clone(pagedata);
|
let copy = $clone(pagedata);
|
||||||
@@ -453,6 +456,7 @@ function createEmptyField() {
|
|||||||
copy.update = { fields: copy.fields };
|
copy.update = { fields: copy.fields };
|
||||||
store.commit(props.pagename, copy);
|
store.commit(props.pagename, copy);
|
||||||
//pagedata = copy
|
//pagedata = copy
|
||||||
|
console.log("field", field);
|
||||||
emit("newfield", field);
|
emit("newfield", field);
|
||||||
label = undefined;
|
label = undefined;
|
||||||
name = `f${$id()}`;
|
name = `f${$id()}`;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<table class="table">
|
<table class="table is-fullwidth">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="fs-14">
|
<tr class="fs-14">
|
||||||
<th>#</th>
|
<th>#</th>
|
||||||
<th>Tên trường</th>
|
<th>Tên trường</th>
|
||||||
<th>Tên cột</th>
|
<th>Tên cột</th>
|
||||||
<th>...</th>
|
<th class="is-narrow">...</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -23,21 +23,47 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>{{ $stripHtml(v.label, 50) }}</td>
|
<td>{{ $stripHtml(v.label, 50) }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a
|
<div class="field has-addons">
|
||||||
class="mr-4"
|
<p class="control">
|
||||||
|
<button
|
||||||
|
class="button is-primary is-light"
|
||||||
@click="moveDown(v, i)"
|
@click="moveDown(v, i)"
|
||||||
>
|
>
|
||||||
<SvgIcon v-bind="{ name: 'down1.png', type: 'dark', size: 18 }"></SvgIcon>
|
<span class="icon">
|
||||||
</a>
|
<Icon
|
||||||
<a
|
name="material-symbols:arrow-downward-rounded"
|
||||||
class="mr-4"
|
:size="19"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
<p class="control">
|
||||||
|
<button
|
||||||
|
class="button is-primary is-light"
|
||||||
@click="moveUp(v, i)"
|
@click="moveUp(v, i)"
|
||||||
>
|
>
|
||||||
<SvgIcon v-bind="{ name: 'up.png', type: 'dark', size: 18 }"></SvgIcon>
|
<span class="icon">
|
||||||
</a>
|
<Icon
|
||||||
<a @click="askConfirm(v, i)">
|
name="material-symbols:arrow-upward-rounded"
|
||||||
<SvgIcon v-bind="{ name: 'bin1.svg', type: 'dark', size: 18 }"></SvgIcon>
|
:size="19"
|
||||||
</a>
|
/>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
<p class="control">
|
||||||
|
<button
|
||||||
|
class="button is-primary is-light"
|
||||||
|
@click="askConfirm(v, i)"
|
||||||
|
>
|
||||||
|
<span class="icon">
|
||||||
|
<Icon
|
||||||
|
name="material-symbols:delete-outline-rounded"
|
||||||
|
:size="19"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -1,33 +1,38 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="field is-horizontal">
|
<div class="fixed-grid has-12-cols">
|
||||||
<div class="field-body">
|
<div class="grid">
|
||||||
<div class="field">
|
<div class="cell is-col-span-4">
|
||||||
<label class="label fs-14"> Cỡ chữ của bảng <span class="has-text-danger"> * </span></label>
|
<div class="box">
|
||||||
|
<label class="label fs-14">Cỡ chữ của bảng</label>
|
||||||
<p class="control fs-14">
|
<p class="control fs-14">
|
||||||
<input
|
<input
|
||||||
class="input is-small"
|
class="input fs-13"
|
||||||
type="text"
|
type="text"
|
||||||
:value="tablesetting.find((v) => v.code === 'table-font-size').detail"
|
:value="tablesetting.find((v) => v.code === 'table-font-size').detail"
|
||||||
@change="changeSetting($event.target.value, 'table-font-size')"
|
@change="changeSetting($event.target.value, 'table-font-size')"
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
</div>
|
||||||
<label class="label fs-14"> Cỡ chữ tiêu đề <span class="has-text-danger"> * </span></label>
|
<div class="cell is-col-span-4">
|
||||||
<p class="control fs-14">
|
<div class="box">
|
||||||
|
<label class="label fs-14">Cỡ chữ tiêu đề</label>
|
||||||
|
<p class="control">
|
||||||
<input
|
<input
|
||||||
class="input is-small"
|
class="input fs-13"
|
||||||
type="text"
|
type="text"
|
||||||
:value="tablesetting.find((v) => v.code === 'header-font-size').detail"
|
:value="tablesetting.find((v) => v.code === 'header-font-size').detail"
|
||||||
@change="changeSetting($event.target.value, 'header-font-size')"
|
@change="changeSetting($event.target.value, 'header-font-size')"
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
</div>
|
||||||
<label class="label fs-14"> Số dòng trên 1 trang <span class="has-text-danger"> * </span> </label>
|
<div class="cell is-col-span-4">
|
||||||
<p class="control fs-14">
|
<div class="box">
|
||||||
|
<label class="label fs-14">Số dòng trên 1 trang</label>
|
||||||
|
<p class="control">
|
||||||
<input
|
<input
|
||||||
class="input is-small"
|
class="input fs-13"
|
||||||
type="text"
|
type="text"
|
||||||
:value="tablesetting.find((v) => v.code === 'per-page').detail"
|
:value="tablesetting.find((v) => v.code === 'per-page').detail"
|
||||||
@change="changeSetting($event.target.value, 'per-page')"
|
@change="changeSetting($event.target.value, 'per-page')"
|
||||||
@@ -35,72 +40,115 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="cell is-col-span-6">
|
||||||
<div class="field is-horizontal mt-5">
|
<div class="box">
|
||||||
<div class="field-body">
|
<label class="label fs-14">Màu nền bảng</label>
|
||||||
<div class="field">
|
<p class="control is-flex is-gap-1">
|
||||||
<label class="label fs-14"> Màu nền bảng <span class="has-text-danger"> * </span> </label>
|
|
||||||
<p class="control fs-14">
|
|
||||||
<input
|
<input
|
||||||
type="color"
|
type="color"
|
||||||
:value="tablesetting.find((v) => v.code === 'table-background').detail"
|
:value="tablesetting.find((v) => v.code === 'table-background').detail"
|
||||||
@change="changeSetting($event.target.value, 'table-background')"
|
@change="changeSetting($event.target.value, 'table-background')"
|
||||||
/>
|
/>
|
||||||
|
<input
|
||||||
|
class="input fs-13"
|
||||||
|
type="text"
|
||||||
|
placeholder="#f29384, var(--bulma-blue)"
|
||||||
|
:value="tablesetting.find((v) => v.code === 'table-background').detail"
|
||||||
|
@change="changeSetting($event.target.value, 'table-background')"
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
</div>
|
||||||
<label class="label fs-14"> Màu chữ <span class="has-text-danger"> * </span> </label>
|
<div class="cell is-col-span-6">
|
||||||
<p class="control fs-14">
|
<div class="box">
|
||||||
|
<label class="label fs-14">Màu chữ</label>
|
||||||
|
<p class="control is-flex is-gap-1">
|
||||||
<input
|
<input
|
||||||
type="color"
|
type="color"
|
||||||
:value="tablesetting.find((v) => v.code === 'table-font-color').detail"
|
:value="tablesetting.find((v) => v.code === 'table-font-color').detail"
|
||||||
@change="changeSetting($event.target.value, 'table-font-color')"
|
@change="changeSetting($event.target.value, 'table-font-color')"
|
||||||
/>
|
/>
|
||||||
|
<input
|
||||||
|
class="input fs-13"
|
||||||
|
type="text"
|
||||||
|
placeholder="#f29384, var(--bulma-blue)"
|
||||||
|
:value="tablesetting.find((v) => v.code === 'table-font-color').detail"
|
||||||
|
@change="changeSetting($event.target.value, 'table-font-color')"
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="cell is-col-span-6">
|
||||||
<div class="field is-horizontal mt-5">
|
<div class="box">
|
||||||
<div class="field-body">
|
<label class="label fs-14">Màu chữ tiêu đề</label>
|
||||||
<div class="field">
|
<p class="control is-flex is-gap-1">
|
||||||
<label class="label fs-14"> Màu chữ tiêu đề <span class="has-text-danger"> * </span> </label>
|
|
||||||
<p class="control fs-14">
|
|
||||||
<input
|
<input
|
||||||
type="color"
|
type="color"
|
||||||
:value="tablesetting.find((v) => v.code === 'header-font-color').detail"
|
:value="tablesetting.find((v) => v.code === 'header-font-color').detail"
|
||||||
@change="changeSetting($event.target.value, 'header-font-color')"
|
@change="changeSetting($event.target.value, 'header-font-color')"
|
||||||
/>
|
/>
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<label class="label fs-14"> Màu nền tiêu đề <span class="has-text-danger"> * </span> </label>
|
|
||||||
<p class="control fs-14">
|
|
||||||
<input
|
<input
|
||||||
type="color"
|
class="input fs-13"
|
||||||
:value="tablesetting.find((v) => v.code === 'header-background').detail"
|
type="text"
|
||||||
@change="changeSetting($event.target.value, 'header-background')"
|
placeholder="#f29384, var(--bulma-blue)"
|
||||||
|
:value="tablesetting.find((v) => v.code === 'header-font-color').detail"
|
||||||
|
@change="changeSetting($event.target.value, 'header-font-color')"
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
</div>
|
||||||
<label class="label fs-14"> Màu chữ khi filter<span class="has-text-danger"> * </span> </label>
|
<div class="cell is-col-span-6">
|
||||||
<p class="control fs-14">
|
<div class="box">
|
||||||
|
<label class="label fs-14">Màu nền tiêu đề</label>
|
||||||
|
<div class="control is-flex is-gap-1 is-align-items-stretch">
|
||||||
<input
|
<input
|
||||||
type="color"
|
type="color"
|
||||||
|
:value="rgbToHex(headerBg)"
|
||||||
|
@change="changeSetting($event.target.value, 'header-background')"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
class="input fs-13 h-full"
|
||||||
|
type="text"
|
||||||
|
placeholder="#f29384, var(--bulma-blue)"
|
||||||
|
:value="tablesetting.find((v) => v.code === 'header-background').detail"
|
||||||
|
@change="changeSetting($event.target.value, 'header-background')"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
ref="renderedHeaderBg"
|
||||||
|
class="is-hidden"
|
||||||
|
:style="{
|
||||||
|
backgroundColor: tablesetting.find((v) => v.code === 'header-background').detail,
|
||||||
|
}"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell is-col-span-6">
|
||||||
|
<div class="box">
|
||||||
|
<label class="label fs-14">Màu chữ khi filter</label>
|
||||||
|
<p class="control is-flex is-gap-1">
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
:value="tablesetting.find((v) => v.code === 'header-filter-color').detail"
|
||||||
|
@change="changeSetting($event.target.value, 'header-filter-color')"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
class="input fs-13"
|
||||||
|
type="text"
|
||||||
|
placeholder="#f29384, var(--bulma-blue)"
|
||||||
:value="tablesetting.find((v) => v.code === 'header-filter-color').detail"
|
:value="tablesetting.find((v) => v.code === 'header-filter-color').detail"
|
||||||
@change="changeSetting($event.target.value, 'header-filter-color')"
|
@change="changeSetting($event.target.value, 'header-filter-color')"
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="cell is-col-span-6">
|
||||||
<div class="field is-horizontal mt-5">
|
<div class="box">
|
||||||
<div class="field-body">
|
<label class="label fs-14">Đường viền</label>
|
||||||
<div class="field">
|
|
||||||
<label class="label fs-14"> Đường viền <span class="has-text-danger"> * </span> </label>
|
|
||||||
<p class="control fs-14">
|
<p class="control fs-14">
|
||||||
<input
|
<input
|
||||||
class="input is-small"
|
class="input fs-13"
|
||||||
type="text"
|
type="text"
|
||||||
:value="
|
:value="
|
||||||
tablesetting.find((v) => v.code === 'td-border')
|
tablesetting.find((v) => v.code === 'td-border')
|
||||||
@@ -113,20 +161,30 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="button is-primary"
|
||||||
|
@click="emit('close')"
|
||||||
|
>
|
||||||
|
Cập nhật
|
||||||
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useStore } from "@/stores/index";
|
const props = defineProps({
|
||||||
const store = useStore();
|
|
||||||
var props = defineProps({
|
|
||||||
pagename: String,
|
pagename: String,
|
||||||
});
|
});
|
||||||
const { $copy, $clone, $empty } = useNuxtApp();
|
const emit = defineEmits(["close"]);
|
||||||
var pagedata = $clone(store[props.pagename]);
|
const { $copy, $clone, $empty, $store } = useNuxtApp();
|
||||||
var errors = [];
|
var pagedata = $clone($store[props.pagename]);
|
||||||
var radioNote = "no";
|
if (!Array.isArray(pagedata.tablesetting)) {
|
||||||
|
pagedata.tablesetting = Object.values(pagedata.tablesetting);
|
||||||
|
}
|
||||||
|
const errors = ref([]);
|
||||||
|
let radioNote = "no";
|
||||||
var tablesetting = pagedata.tablesetting;
|
var tablesetting = pagedata.tablesetting;
|
||||||
let found = tablesetting.find((v) => v.code === "note");
|
let found = tablesetting.find((v) => v.code === "note");
|
||||||
if (found ? found.detail !== "@" : false) radioNote = "yes";
|
if (found ? found.detail !== "@" : false) radioNote = "yes";
|
||||||
|
|
||||||
function changeSetting(value, code) {
|
function changeSetting(value, code) {
|
||||||
if (code === "note" && $empty(value)) return;
|
if (code === "note" && $empty(value)) return;
|
||||||
let copy = $copy(tablesetting);
|
let copy = $copy(tablesetting);
|
||||||
@@ -139,6 +197,45 @@ function changeSetting(value, code) {
|
|||||||
}
|
}
|
||||||
tablesetting = copy;
|
tablesetting = copy;
|
||||||
pagedata.tablesetting = tablesetting;
|
pagedata.tablesetting = tablesetting;
|
||||||
store.commit(props.pagename, pagedata);
|
$store.commit(props.pagename, pagedata);
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderedHeaderBg = useTemplateRef("renderedHeaderBg");
|
||||||
|
const headerBg = ref("#000000");
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
headerBg.value = window.getComputedStyle(renderedHeaderBg.value).backgroundColor;
|
||||||
|
});
|
||||||
|
watch();
|
||||||
|
|
||||||
|
function rgbToHex(rgb) {
|
||||||
|
const [r, g, b] = rgb.match(/\d+/g);
|
||||||
|
return "#" + [r, g, b].map((x) => Number(x).toString(16).padStart(2, "0")).join("");
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
input[type="color"] {
|
||||||
|
width: var(--bulma-control-height);
|
||||||
|
min-width: var(--bulma-control-height);
|
||||||
|
max-width: var(--bulma-control-height);
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
input[type="color"]::-webkit-color-swatch-wrapper {
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
input[type="color"]::-webkit-color-swatch {
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid var(--bulma-grey-90);
|
||||||
|
background-color: var(--bulma-grey-95);
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ const body = ref({
|
|||||||
});
|
});
|
||||||
|
|
||||||
function selected(field, data) {
|
function selected(field, data) {
|
||||||
body.value[field] = data.id;
|
if (data === null) body.value[field] = data;
|
||||||
|
else body.value[field] = data.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createProduct() {
|
async function createProduct() {
|
||||||
@@ -31,8 +32,6 @@ async function createProduct() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
|
||||||
<h1 class="subtitle is-4">AddProductForm</h1>
|
|
||||||
<form class="fixed-grid has-12-cols">
|
<form class="fixed-grid has-12-cols">
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<div class="cell is-col-span-8">
|
<div class="cell is-col-span-8">
|
||||||
@@ -57,6 +56,7 @@ async function createProduct() {
|
|||||||
field: 'name',
|
field: 'name',
|
||||||
column: ['name'],
|
column: ['name'],
|
||||||
first: true,
|
first: true,
|
||||||
|
clearable: true,
|
||||||
placeholder: 'OS',
|
placeholder: 'OS',
|
||||||
addon: {
|
addon: {
|
||||||
component: 'imports/addons/AddOS',
|
component: 'imports/addons/AddOS',
|
||||||
@@ -78,6 +78,7 @@ async function createProduct() {
|
|||||||
field: 'name',
|
field: 'name',
|
||||||
column: ['name'],
|
column: ['name'],
|
||||||
first: true,
|
first: true,
|
||||||
|
clearable: true,
|
||||||
placeholder: 'Hãng',
|
placeholder: 'Hãng',
|
||||||
addon: {
|
addon: {
|
||||||
component: 'imports/addons/AddManufacturer',
|
component: 'imports/addons/AddManufacturer',
|
||||||
@@ -99,6 +100,7 @@ async function createProduct() {
|
|||||||
field: 'code',
|
field: 'code',
|
||||||
column: ['code'],
|
column: ['code'],
|
||||||
first: true,
|
first: true,
|
||||||
|
clearable: true,
|
||||||
placeholder: 'Pin',
|
placeholder: 'Pin',
|
||||||
addon: {
|
addon: {
|
||||||
component: 'imports/addons/AddBattery',
|
component: 'imports/addons/AddBattery',
|
||||||
@@ -117,9 +119,10 @@ async function createProduct() {
|
|||||||
<SearchBox
|
<SearchBox
|
||||||
v-bind="{
|
v-bind="{
|
||||||
api: 'Screen',
|
api: 'Screen',
|
||||||
field: 'code',
|
field: 'label',
|
||||||
column: ['code'],
|
column: ['resolution', 'standard', 'technology'],
|
||||||
first: true,
|
first: true,
|
||||||
|
clearable: true,
|
||||||
placeholder: 'Màn hình',
|
placeholder: 'Màn hình',
|
||||||
addon: {
|
addon: {
|
||||||
component: 'imports/addons/AddScreen',
|
component: 'imports/addons/AddScreen',
|
||||||
@@ -141,6 +144,7 @@ async function createProduct() {
|
|||||||
field: 'name',
|
field: 'name',
|
||||||
column: ['name'],
|
column: ['name'],
|
||||||
first: true,
|
first: true,
|
||||||
|
clearable: true,
|
||||||
placeholder: 'CPU',
|
placeholder: 'CPU',
|
||||||
addon: {
|
addon: {
|
||||||
component: 'imports/addons/AddCPU',
|
component: 'imports/addons/AddCPU',
|
||||||
@@ -162,6 +166,7 @@ async function createProduct() {
|
|||||||
field: 'name',
|
field: 'name',
|
||||||
column: ['name'],
|
column: ['name'],
|
||||||
first: true,
|
first: true,
|
||||||
|
clearable: true,
|
||||||
placeholder: 'GPU',
|
placeholder: 'GPU',
|
||||||
addon: {
|
addon: {
|
||||||
component: 'imports/addons/AddGPU',
|
component: 'imports/addons/AddGPU',
|
||||||
@@ -183,6 +188,7 @@ async function createProduct() {
|
|||||||
field: 'code',
|
field: 'code',
|
||||||
column: ['code'],
|
column: ['code'],
|
||||||
first: true,
|
first: true,
|
||||||
|
clearable: true,
|
||||||
placeholder: 'Camera',
|
placeholder: 'Camera',
|
||||||
addon: {
|
addon: {
|
||||||
component: 'imports/addons/AddCamera',
|
component: 'imports/addons/AddCamera',
|
||||||
@@ -204,6 +210,7 @@ async function createProduct() {
|
|||||||
field: 'code',
|
field: 'code',
|
||||||
column: ['code'],
|
column: ['code'],
|
||||||
first: true,
|
first: true,
|
||||||
|
clearable: true,
|
||||||
placeholder: 'SIM',
|
placeholder: 'SIM',
|
||||||
addon: {
|
addon: {
|
||||||
component: 'imports/addons/AddSIM',
|
component: 'imports/addons/AddSIM',
|
||||||
@@ -225,6 +232,7 @@ async function createProduct() {
|
|||||||
field: 'name',
|
field: 'name',
|
||||||
column: ['name'],
|
column: ['name'],
|
||||||
first: true,
|
first: true,
|
||||||
|
clearable: true,
|
||||||
placeholder: 'Kết nối',
|
placeholder: 'Kết nối',
|
||||||
addon: {
|
addon: {
|
||||||
component: 'imports/addons/AddNetworkTechnology',
|
component: 'imports/addons/AddNetworkTechnology',
|
||||||
@@ -246,6 +254,7 @@ async function createProduct() {
|
|||||||
field: 'code',
|
field: 'code',
|
||||||
column: ['code'],
|
column: ['code'],
|
||||||
first: true,
|
first: true,
|
||||||
|
clearable: true,
|
||||||
placeholder: 'Công nghệ sạc',
|
placeholder: 'Công nghệ sạc',
|
||||||
addon: {
|
addon: {
|
||||||
component: 'imports/addons/AddChargingTechnology',
|
component: 'imports/addons/AddChargingTechnology',
|
||||||
@@ -267,6 +276,7 @@ async function createProduct() {
|
|||||||
field: 'code',
|
field: 'code',
|
||||||
column: ['code'],
|
column: ['code'],
|
||||||
first: true,
|
first: true,
|
||||||
|
clearable: true,
|
||||||
placeholder: 'Bộ nhớ ngoài',
|
placeholder: 'Bộ nhớ ngoài',
|
||||||
addon: {
|
addon: {
|
||||||
component: 'imports/addons/AddExternalStorage',
|
component: 'imports/addons/AddExternalStorage',
|
||||||
@@ -288,6 +298,7 @@ async function createProduct() {
|
|||||||
field: 'name',
|
field: 'name',
|
||||||
column: ['name'],
|
column: ['name'],
|
||||||
first: true,
|
first: true,
|
||||||
|
clearable: true,
|
||||||
placeholder: 'Chỉ số IP',
|
placeholder: 'Chỉ số IP',
|
||||||
addon: {
|
addon: {
|
||||||
component: 'imports/addons/AddIPRating',
|
component: 'imports/addons/AddIPRating',
|
||||||
@@ -309,6 +320,7 @@ async function createProduct() {
|
|||||||
field: 'label',
|
field: 'label',
|
||||||
column: ['frame_material', 'back_material'],
|
column: ['frame_material', 'back_material'],
|
||||||
first: true,
|
first: true,
|
||||||
|
clearable: true,
|
||||||
placeholder: 'Chất liệu',
|
placeholder: 'Chất liệu',
|
||||||
addon: {
|
addon: {
|
||||||
component: 'imports/addons/AddDesign',
|
component: 'imports/addons/AddDesign',
|
||||||
@@ -328,12 +340,11 @@ async function createProduct() {
|
|||||||
@click.prevent="createProduct"
|
@click.prevent="createProduct"
|
||||||
>
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<Icon name="material-symbols:add-2-rounded" />
|
<Icon name="material-symbols:add-rounded" />
|
||||||
</span>
|
</span>
|
||||||
<span>Tạo sản phẩm</span>
|
<span>Tạo sản phẩm</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
61
app/components/imports/AddProductVariant.vue
Normal file
61
app/components/imports/AddProductVariant.vue
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<script setup>
|
||||||
|
import DataView from "@/components/datatable/DataView.vue";
|
||||||
|
import AddProductVariantForm from "@/components/imports/AddProductVariantForm.vue";
|
||||||
|
const product = ref();
|
||||||
|
const key = ref(0);
|
||||||
|
watch(product, () => {
|
||||||
|
key.value++;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="fixed-grid has-12-cols">
|
||||||
|
<div class="grid">
|
||||||
|
<div class="cell is-col-span-6 is-col-start-4">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">Sản phẩm</label>
|
||||||
|
<SearchBox
|
||||||
|
v-bind="{
|
||||||
|
api: 'product',
|
||||||
|
field: 'name',
|
||||||
|
column: ['name'],
|
||||||
|
first: true,
|
||||||
|
clearable: true,
|
||||||
|
placeholder: 'Tìm sản phẩm',
|
||||||
|
addon: {
|
||||||
|
component: 'imports/AddProductForm',
|
||||||
|
width: '90%',
|
||||||
|
height: 'auto',
|
||||||
|
title: 'Thêm sản phẩm',
|
||||||
|
},
|
||||||
|
}"
|
||||||
|
@option="product = $event"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="product"
|
||||||
|
class="cell is-col-span-12"
|
||||||
|
>
|
||||||
|
<DataView
|
||||||
|
:key="key"
|
||||||
|
v-bind="{
|
||||||
|
api: 'Product_Variant',
|
||||||
|
setting: 'product-variants',
|
||||||
|
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',
|
||||||
|
filter: { product: product.id },
|
||||||
|
},
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<AddProductVariantForm
|
||||||
|
v-if="product"
|
||||||
|
:productId="product.id"
|
||||||
|
@created="key++"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -1,20 +1,33 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import InputNumber from "@/components/common/InputNumber.vue";
|
import InputNumber from "@/components/common/InputNumber.vue";
|
||||||
|
import { omitBy } from "es-toolkit";
|
||||||
|
|
||||||
const { $insertapi } = useNuxtApp();
|
const props = defineProps({
|
||||||
|
productId: Number,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["created"]);
|
||||||
|
|
||||||
|
const { $empty, $insertapi } = useNuxtApp();
|
||||||
const isPending = ref(false);
|
const isPending = ref(false);
|
||||||
const body = ref({
|
const body = ref({
|
||||||
product: null,
|
product: props.productId,
|
||||||
price: null,
|
price: null,
|
||||||
internal_storage: null,
|
internal_storage: null,
|
||||||
ram: null,
|
ram: null,
|
||||||
color: null,
|
color: null,
|
||||||
note: null,
|
note: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.productId,
|
||||||
|
(newVal) => {
|
||||||
|
body.value.product = props.productId;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
function selected(field, data) {
|
function selected(field, data) {
|
||||||
if (field === "price") {
|
if (data === null || field === "price") {
|
||||||
body.value[field] = data;
|
body.value[field] = data;
|
||||||
} else {
|
} else {
|
||||||
body.value[field] = data.id;
|
body.value[field] = data.id;
|
||||||
@@ -23,38 +36,21 @@ function selected(field, data) {
|
|||||||
|
|
||||||
async function createProductVariant() {
|
async function createProductVariant() {
|
||||||
isPending.value = true;
|
isPending.value = true;
|
||||||
const res = await $insertapi("Product_Variant", body.value);
|
const trimmedBody = omitBy(body.value, $empty);
|
||||||
|
const res = await $insertapi("Product_Variant", trimmedBody);
|
||||||
isPending.value = false;
|
isPending.value = false;
|
||||||
|
if (res !== "error") {
|
||||||
|
emit("created");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="subtitle is-4">AddProductVariantForm</h1>
|
<h1 class="subtitle">Thêm phiên bản</h1>
|
||||||
<form class="fixed-grid has-12-cols">
|
<form class="fixed-grid has-12-cols">
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<div class="cell is-col-span-8">
|
<div class="cell is-col-span-3">
|
||||||
<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',
|
|
||||||
addon: {
|
|
||||||
component: 'imports/AddProductForm',
|
|
||||||
width: '90%',
|
|
||||||
height: 'auto',
|
|
||||||
title: 'Thêm sản phẩm',
|
|
||||||
},
|
|
||||||
}"
|
|
||||||
@option="selected('product', $event)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="cell is-col-span-4">
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Đơn giá</label>
|
<label class="label">Đơn giá</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
@@ -70,15 +66,16 @@ async function createProductVariant() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell is-col-span-4">
|
<div class="cell is-col-span-3">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Màu sắc</label>
|
<label class="label">Màu sắc</label>
|
||||||
<SearchBox
|
<SearchBox
|
||||||
v-bind="{
|
v-bind="{
|
||||||
api: 'color',
|
api: 'Color',
|
||||||
field: 'name',
|
field: 'name',
|
||||||
column: ['name'],
|
column: ['name'],
|
||||||
first: true,
|
first: true,
|
||||||
|
clearable: true,
|
||||||
placeholder: 'Màu sắc',
|
placeholder: 'Màu sắc',
|
||||||
addon: {
|
addon: {
|
||||||
component: 'imports/addons/AddColor',
|
component: 'imports/addons/AddColor',
|
||||||
@@ -91,7 +88,7 @@ async function createProductVariant() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell is-col-span-4">
|
<div class="cell is-col-span-3">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">RAM</label>
|
<label class="label">RAM</label>
|
||||||
<SearchBox
|
<SearchBox
|
||||||
@@ -100,6 +97,7 @@ async function createProductVariant() {
|
|||||||
field: 'code',
|
field: 'code',
|
||||||
column: ['code'],
|
column: ['code'],
|
||||||
first: true,
|
first: true,
|
||||||
|
clearable: true,
|
||||||
placeholder: 'RAM',
|
placeholder: 'RAM',
|
||||||
addon: {
|
addon: {
|
||||||
component: 'imports/addons/AddRAM',
|
component: 'imports/addons/AddRAM',
|
||||||
@@ -112,7 +110,7 @@ async function createProductVariant() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell is-col-span-4">
|
<div class="cell is-col-span-3">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Bộ nhớ trong</label>
|
<label class="label">Bộ nhớ trong</label>
|
||||||
<SearchBox
|
<SearchBox
|
||||||
@@ -121,6 +119,7 @@ async function createProductVariant() {
|
|||||||
field: 'code',
|
field: 'code',
|
||||||
column: ['code'],
|
column: ['code'],
|
||||||
first: true,
|
first: true,
|
||||||
|
clearable: true,
|
||||||
placeholder: 'Bộ nhớ trong',
|
placeholder: 'Bộ nhớ trong',
|
||||||
addon: {
|
addon: {
|
||||||
component: 'imports/addons/AddInternalStorage',
|
component: 'imports/addons/AddInternalStorage',
|
||||||
@@ -148,11 +147,14 @@ async function createProductVariant() {
|
|||||||
<div class="cell is-col-span-12">
|
<div class="cell is-col-span-12">
|
||||||
<button
|
<button
|
||||||
:class="['button is-primary', { 'is-loading': isPending }]"
|
:class="['button is-primary', { 'is-loading': isPending }]"
|
||||||
:disabled="Object.values(body).every((v) => v === null)"
|
:disabled="Object.values(body).every($empty)"
|
||||||
@click.prevent="createProductVariant"
|
@click.prevent="createProductVariant"
|
||||||
>
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<Icon name="material-symbols:add-2-rounded" />
|
<Icon
|
||||||
|
name="material-symbols:add-rounded"
|
||||||
|
:size="18"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span>Thêm phiên bản</span>
|
<span>Thêm phiên bản</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
12
app/components/imports/Color.vue
Normal file
12
app/components/imports/Color.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
color: String,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="w-20 h-4"
|
||||||
|
:style="{ backgroundColor: color, outline: '1px solid var(--bulma-grey-85)' }"
|
||||||
|
></div>
|
||||||
|
</template>
|
||||||
@@ -1,22 +1,43 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import AddProductForm from "@/components/imports/AddProductForm.vue";
|
import AddProductForm from "@/components/imports/AddProductForm.vue";
|
||||||
import AddProductVariantForm from "@/components/imports/AddProductVariantForm.vue";
|
import AddProductVariant from "@/components/imports/AddProductVariant.vue";
|
||||||
import FileUpload from "@/components/media/FileUpload.vue";
|
const menus = [
|
||||||
|
{
|
||||||
|
id: "add-product",
|
||||||
|
name: "Tạo sản phẩm",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "add-product-variant",
|
||||||
|
name: "Thêm phiên bản",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const activeMenu = ref(menus[1]);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FileUpload
|
<div class="fixed-grid has-12-cols">
|
||||||
:type="['file']"
|
<div class="grid is-gap-4">
|
||||||
class="mb-2"
|
<div class="cell is-col-span-2">
|
||||||
@files="onFiles"
|
<aside class="menu">
|
||||||
|
<ul class="menu-list">
|
||||||
|
<li
|
||||||
|
v-for="menu in menus"
|
||||||
|
:key="menu.id"
|
||||||
>
|
>
|
||||||
<template #icon>
|
<a
|
||||||
<Icon
|
@click="activeMenu = menu"
|
||||||
name="material-symbols:upload-rounded"
|
:class="{
|
||||||
:size="20"
|
'is-active': activeMenu.id === menu.id,
|
||||||
/>
|
}"
|
||||||
</template>
|
>{{ menu.name }}</a
|
||||||
<span class="font-medium">Import</span>
|
>
|
||||||
</FileUpload>
|
</li>
|
||||||
<AddProductForm />
|
</ul>
|
||||||
<AddProductVariantForm />
|
</aside>
|
||||||
|
</div>
|
||||||
|
<div class="cell is-col-span-10">
|
||||||
|
<AddProductForm v-if="activeMenu.id === 'add-product'" />
|
||||||
|
<AddProductVariant v-if="activeMenu.id === 'add-product-variant'" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ const inventoryHighlights = [
|
|||||||
<span class="icon">
|
<span class="icon">
|
||||||
<Icon
|
<Icon
|
||||||
:size="18"
|
:size="18"
|
||||||
name="material-symbols:add-2-rounded"
|
name="material-symbols:add-rounded"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span>Điều chỉnh</span>
|
<span>Điều chỉnh</span>
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ const viewMode = ref("list");
|
|||||||
<span class="icon">
|
<span class="icon">
|
||||||
<Icon
|
<Icon
|
||||||
:size="18"
|
:size="18"
|
||||||
name="material-symbols:add-2-rounded"
|
name="material-symbols:add-rounded"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span>Tạo đơn hàng</span>
|
<span>Tạo đơn hàng</span>
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ export default {
|
|||||||
component: "menu/MenuSave",
|
component: "menu/MenuSave",
|
||||||
title: "Lưu thiết lập",
|
title: "Lưu thiết lập",
|
||||||
width: "600px",
|
width: "600px",
|
||||||
height: "300px",
|
height: "auto",
|
||||||
vbind: { pagename: this.pagename3, classify: 3 },
|
vbind: { pagename: this.pagename3, classify: 3 },
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
style="min-height: 100vh"
|
|
||||||
class="has-background-blue-100"
|
|
||||||
data-theme="light"
|
data-theme="light"
|
||||||
lang="vi"
|
lang="vi"
|
||||||
>
|
>
|
||||||
@@ -28,6 +26,7 @@ import { onMounted } from "vue";
|
|||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import SnackBar from "@/components/snackbar/SnackBar.vue";
|
import SnackBar from "@/components/snackbar/SnackBar.vue";
|
||||||
import Modal from "@/components/Modal.vue";
|
import Modal from "@/components/Modal.vue";
|
||||||
|
import { throttle } from "es-toolkit";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { $getdata, $requestLogin, $store } = useNuxtApp();
|
const { $getdata, $requestLogin, $store } = useNuxtApp();
|
||||||
@@ -36,7 +35,7 @@ const snackbar = ref(undefined);
|
|||||||
const showmodal = ref(undefined);
|
const showmodal = ref(undefined);
|
||||||
function getViewport() {
|
function getViewport() {
|
||||||
let viewport;
|
let viewport;
|
||||||
var width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||||||
if (width <= 768)
|
if (width <= 768)
|
||||||
viewport = 1; // 'mobile'
|
viewport = 1; // 'mobile'
|
||||||
else if (width >= 769 && width <= 1023)
|
else if (width >= 769 && width <= 1023)
|
||||||
@@ -91,6 +90,8 @@ async function checkLogin() {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
checkRedirect();
|
checkRedirect();
|
||||||
getViewport();
|
getViewport();
|
||||||
|
const throttledGetViewport = throttle(getViewport, 400);
|
||||||
|
window.addEventListener("resize", throttledGetViewport);
|
||||||
});
|
});
|
||||||
watch(
|
watch(
|
||||||
() => $store.snackbar,
|
() => $store.snackbar,
|
||||||
|
|||||||
@@ -59,6 +59,10 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
useHead({
|
useHead({
|
||||||
link: [{ rel: "icon", type: "image/x-icon", href: "/favicon.svg" }],
|
link: [{ rel: "icon", type: "image/x-icon", href: "/favicon.svg" }],
|
||||||
|
htmlAttrs: {
|
||||||
|
class: "has-background-blue-100",
|
||||||
|
style: "min-height: 100vh",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { $createMeta, $store, $copy, $id } = useNuxtApp();
|
const { $createMeta, $store, $copy, $id } = useNuxtApp();
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ export default defineNuxtPlugin(() => {
|
|||||||
|
|
||||||
//==========Find & filter=================
|
//==========Find & filter=================
|
||||||
const find = function (arr, obj, attr) {
|
const find = function (arr, obj, attr) {
|
||||||
|
if (typeof arr === "object" && !Array.isArray(arr)) {
|
||||||
|
arr = Object.values(arr);
|
||||||
|
}
|
||||||
const keys = Object.keys(obj);
|
const keys = Object.keys(obj);
|
||||||
let found = arr.find((v) => {
|
let found = arr.find((v) => {
|
||||||
let valid = true;
|
let valid = true;
|
||||||
|
|||||||
@@ -1012,7 +1012,16 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
name: "Screen",
|
name: "Screen",
|
||||||
url: "data/Screen/",
|
url: "data/Screen/",
|
||||||
url_detail: "data-detail/Screen/",
|
url_detail: "data-detail/Screen/",
|
||||||
params: {},
|
params: {
|
||||||
|
values: "id,code,resolution,standard,technology,size,create_time",
|
||||||
|
distinct_values: {
|
||||||
|
label: {
|
||||||
|
type: "Concat",
|
||||||
|
field: ["resolution", "standard", "technology"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
summary: "annotate",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "CPU",
|
name: "CPU",
|
||||||
@@ -1078,7 +1087,7 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "color",
|
name: "Color",
|
||||||
url: "data/Color/",
|
url: "data/Color/",
|
||||||
url_detail: "data-detail/Color/",
|
url_detail: "data-detail/Color/",
|
||||||
params: {},
|
params: {},
|
||||||
@@ -1170,7 +1179,7 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
try {
|
try {
|
||||||
let found = findapi(name);
|
let found = findapi(name);
|
||||||
let curpath = found.path ? paths.find((x) => x.name === found.path).url : path;
|
let curpath = found.path ? paths.find((x) => x.name === found.path).url : path;
|
||||||
var rs;
|
let rs;
|
||||||
if (!Array.isArray(data)) {
|
if (!Array.isArray(data)) {
|
||||||
rs = await $fetch(`${curpath}${found.url}`, {
|
rs = await $fetch(`${curpath}${found.url}`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -1241,7 +1250,7 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
? $snackbar("Data has been successfully saved to the system.", "Success", "Success")
|
? $snackbar("Data has been successfully saved to the system.", "Success", "Success")
|
||||||
: $snackbar("Dữ liệu đã được lưu vào hệ thống", "Thành công", "Success");
|
: $snackbar("Dữ liệu đã được lưu vào hệ thống", "Thành công", "Success");
|
||||||
}
|
}
|
||||||
return rs.data;
|
return rs;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
return "error";
|
return "error";
|
||||||
@@ -1450,7 +1459,7 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
let index = copy.findIndex((v) => v.id === id);
|
let index = copy.findIndex((v) => v.id === id);
|
||||||
if (index >= 0) $remove(copy, index);
|
if (index >= 0) $remove(copy, index);
|
||||||
} else {
|
} else {
|
||||||
rs.data.forEach((element) => {
|
rs.forEach((element) => {
|
||||||
let index = copy.findIndex((v) => v.id === element.id);
|
let index = copy.findIndex((v) => v.id === element.id);
|
||||||
if (index >= 0) $remove(copy, index);
|
if (index >= 0) $remove(copy, index);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import AddDesign from "@/components/imports/addons/AddDesign.vue";
|
|||||||
import AddColor from "@/components/imports/addons/AddColor.vue";
|
import AddColor from "@/components/imports/addons/AddColor.vue";
|
||||||
import AddRAM from "@/components/imports/addons/AddRAM.vue";
|
import AddRAM from "@/components/imports/addons/AddRAM.vue";
|
||||||
import AddInternalStorage from "@/components/imports/addons/AddInternalStorage.vue";
|
import AddInternalStorage from "@/components/imports/addons/AddInternalStorage.vue";
|
||||||
|
import Color from "@/components/imports/Color.vue";
|
||||||
import Returns from "@/components/imports/Returns.vue";
|
import Returns from "@/components/imports/Returns.vue";
|
||||||
import Exports from "@/components/exports/Exports.vue";
|
import Exports from "@/components/exports/Exports.vue";
|
||||||
import ExportsDamaged from "@/components/exports/ExportsDamaged.vue";
|
import ExportsDamaged from "@/components/exports/ExportsDamaged.vue";
|
||||||
@@ -177,6 +178,7 @@ const components = {
|
|||||||
AddColor,
|
AddColor,
|
||||||
AddRAM,
|
AddRAM,
|
||||||
AddInternalStorage,
|
AddInternalStorage,
|
||||||
|
Color,
|
||||||
Returns,
|
Returns,
|
||||||
Exports,
|
Exports,
|
||||||
ExportsDamaged,
|
ExportsDamaged,
|
||||||
|
|||||||
Reference in New Issue
Block a user