This commit is contained in:
Viet An
2026-07-02 16:20:37 +07:00
parent 6d9dce38cb
commit 5e6cb7a551
10 changed files with 463 additions and 419 deletions

View File

@@ -1,387 +1,324 @@
<template>
<div class="toolbar field has-addons is-justify-content-center">
<!-- <div class="control">
<button
class="button is-light is-primary"
@click="checkFilter() ? false : $emit('modalevent', { name: 'dosort', data: 'az' })"
>
<span class="icon">
<Icon
name="mdi:sort-alphabetical-ascending"
:size="22"
:class="checkFilter() && 'has-text-grey-70'"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 25px"
>Sắp xếp tăng dần</span
>
</div>
<div class="control">
<button
class="button is-light is-primary"
@click="checkFilter() ? false : $emit('modalevent', { name: 'dosort', data: 'za' })"
>
<span class="icon">
<Icon
name="mdi:sort-alphabetical-descending"
:size="22"
:class="checkFilter() && 'has-text-grey-70'"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 25px"
>Sắp xếp giảm dần</span
>
</div> -->
<div class="control">
<button
class="button"
@click="moveLeft()"
>
<span class="icon">
<Icon
name="material-symbols:arrow-back-rounded"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Chuyển cột sang trái</span
>
</div>
<div class="control">
<button
class="button"
@click="moveRight()"
>
<span class="icon">
<Icon
name="material-symbols:arrow-forward-rounded"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Chuyển cột sang phải</span
>
</div>
<div class="control">
<button
class="button"
@click="resizeWidth()"
>
<span class="icon">
<Icon
name="fluent:arrow-fit-16-regular"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Tăng độ rộng cột</span
>
</div>
<div class="control">
<button
class="button"
@click="resizeWidth(true)"
>
<span class="icon">
<Icon
name="fluent:arrow-fit-in-16-regular"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Giảm độ rộng cột</span
>
</div>
<div class="control">
<button
class="button"
@click="hideField()"
>
<span class="icon">
<Icon
name="material-symbols:visibility-off-outline-rounded"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Ẩn cột</span
>
</div>
<div class="control">
<button
class="button"
@click="!currentField.mandatory && doRemove()"
>
<span class="icon">
<Icon
name="material-symbols:delete-outline-rounded"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Xóa cột</span
>
</div>
<div class="control">
<button
class="button"
@click="$copyToClipboard(currentField.name)"
>
<span class="icon">
<Icon
name="material-symbols:content-copy-outline-rounded"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Sao chép cột</span
>
</div>
<div class="control">
<button
class="button"
@click="fieldList()"
>
<span class="icon">
<Icon
name="material-symbols:view-column-outline-rounded"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Danh sách cột</span
>
</div>
<div class="control">
<button
class="button"
@click="createField()"
>
<span class="icon">
<Icon
name="material-symbols:add-rounded"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Tạo cột mới</span
>
</div>
<div class="control">
<button
class="button"
@click="tableOption()"
>
<span class="icon">
<Icon
name="material-symbols:table-edit-outline"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; right: 0"
>Tùy chọn bảng</span
>
</div>
<div class="control">
<button
class="button is-primary"
@click="saveSetting()"
>
<span class="icon">
<Icon
name="material-symbols:save-rounded"
:size="20"
/>
</span>
</button>
<p
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; right: 0"
>
Lưu thiết lập
</p>
</div>
</div>
<div class="tabs">
<ul>
<li
v-for="(v, i) in getMenu().filter((x) =>
currentField.format === 'number'
? currentField.formula
? true
: x.code !== 'formula'
: !['filter', 'formula'].find((y) => y === x.code),
)"
:key="i"
:class="selectTab.code === v.code ? 'is-active' : 'has-text-primary'"
@click="changeTab(v)"
>
<a class="py-1.5 fs-14">{{ v.name }}</a>
</li>
</ul>
</div>
<div v-if="currentTab === 'detail'">
<p class="field fs-14 is-flex is-gap-0.5 is-align-items-center">
<span class="font-semibold">Tên trường:</span>
<span>{{ currentField.name }}</span>
<button
class="button is-small size-8 is-primary is-light is-rounded"
@click="$copyToClipboard(currentField.name)"
>
<span class="icon">
<Icon
name="material-symbols:content-copy-outline-rounded"
:size="16"
/>
</span>
</button>
</p>
<div class="field">
<label class="label fs-14">Mô tả<span class="has-text-danger"> *</span></label>
<div class="control">
<div class="field has-addons">
<div class="control is-expanded">
<input
class="input fs-14 h-full"
type="text"
@change="changeLabel($event.target.value)"
v-model="label"
/>
</div>
<div class="control">
<button
class="button h-full"
@click="editLabel()"
>
<span class="icon">
<Icon
name="material-symbols:edit-outline-rounded"
:size="18"
/>
</span>
</button>
</div>
</div>
</div>
<p
v-if="errors.find((v) => v.name === 'label')"
class="help is-danger"
>
{{ errors.find((v) => v.name === "label").msg }}
</p>
</div>
<div class="field">
<label class="label fs-14">Kiểu dữ liệu<span class="has-text-danger"> * </span></label>
<div class="control is-flex is-gap-0.5">
<div class="is-flex is-flex-direction-column max-h-full">
<div class="is-flex-shrink-0 toolbar field has-addons is-justify-content-center">
<!-- <div class="control">
<button
v-for="(v, i) in datatype"
:key="i"
:class="['button fs-14', radioType === v ? 'is-primary is-light' : 'is-white']"
class="button is-light is-primary"
@click="checkFilter() ? false : $emit('modalevent', { name: 'dosort', data: 'az' })"
>
<span class="icon">
<Icon
:name="
radioType === v
? 'material-symbols:radio-button-checked-outline'
: 'material-symbols:radio-button-unchecked'
"
name="mdi:sort-alphabetical-ascending"
:size="22"
:class="checkFilter() && 'has-text-grey-70'"
/>
</span>
<span>{{ v.name }}</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 25px"
>Sắp xếp tăng dần</span
>
</div>
<div class="control">
<button
class="button is-light is-primary"
@click="checkFilter() ? false : $emit('modalevent', { name: 'dosort', data: 'za' })"
>
<span class="icon">
<Icon
name="mdi:sort-alphabetical-descending"
:size="22"
:class="checkFilter() && 'has-text-grey-70'"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 25px"
>Sắp xếp giảm dần</span
>
</div> -->
<div class="control">
<button
class="button"
@click="moveLeft()"
>
<span class="icon">
<Icon
name="material-symbols:arrow-back-rounded"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Chuyển cột sang trái</span
>
</div>
<div class="control">
<button
class="button"
@click="moveRight()"
>
<span class="icon">
<Icon
name="material-symbols:arrow-forward-rounded"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Chuyển cột sang phải</span
>
</div>
<div class="control">
<button
class="button"
@click="resizeWidth()"
>
<span class="icon">
<Icon
name="fluent:arrow-fit-16-regular"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Tăng độ rộng cột</span
>
</div>
<div class="control">
<button
class="button"
@click="resizeWidth(true)"
>
<span class="icon">
<Icon
name="fluent:arrow-fit-in-16-regular"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Giảm độ rộng cột</span
>
</div>
<div class="control">
<button
class="button"
@click="hideField()"
>
<span class="icon">
<Icon
name="material-symbols:visibility-off-outline-rounded"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Ẩn cột</span
>
</div>
<div class="control">
<button
class="button"
@click="!currentField.mandatory && doRemove()"
>
<span class="icon">
<Icon
name="material-symbols:delete-outline-rounded"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Xóa cột</span
>
</div>
<div class="control">
<button
class="button"
@click="$copyToClipboard(currentField.name)"
>
<span class="icon">
<Icon
name="material-symbols:content-copy-outline-rounded"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Sao chép cột</span
>
</div>
<div class="control">
<button
class="button"
@click="fieldList()"
>
<span class="icon">
<Icon
name="material-symbols:view-column-outline-rounded"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Danh sách cột</span
>
</div>
<div class="control">
<button
class="button"
@click="createField()"
>
<span class="icon">
<Icon
name="material-symbols:add-rounded"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; left: 0"
>Tạo cột mới</span
>
</div>
<div class="control">
<button
class="button"
@click="tableOption()"
>
<span class="icon">
<Icon
name="material-symbols:table-edit-outline"
:size="20"
/>
</span>
</button>
<span
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; right: 0"
>Tùy chọn bảng</span
>
</div>
<div class="control">
<button
class="button is-primary"
@click="saveSetting()"
>
<span class="icon">
<Icon
name="material-symbols:save-rounded"
:size="20"
/>
</span>
</button>
<p
class="tooltiptext"
style="top: 110%; bottom: unset; min-width: max-content; right: 0"
>
Lưu thiết lập
</p>
</div>
</div>
<div
v-if="currentField.format === 'number'"
class="field is-horizontal"
>
<div class="field-body">
<div class="field">
<label class="label fs-14">Đơn vị <span class="has-text-danger"> * </span> </label>
<div class="control">
<SearchBox
v-bind="{
vdata: moneyunit,
field: 'name',
column: ['name'],
first: true,
position: 'is-top-left',
}"
@option="selected('_account', $event)"
/>
</div>
<p
class="help has-text-danger"
v-if="errors.find((v) => v.name === 'unit')"
>
{{ errors.find((v) => v.name === "unit").msg }}
</p>
</div>
<div class="field is-narrow">
<label class="label fs-14">Phần thập phân</label>
<div class="control">
<input
class="input"
type="text"
placeholder=""
v-model="decimal"
@input="changeDecimal($event.target.value)"
/>
</div>
</div>
</div>
<div class="is-flex-shrink-0 tabs">
<ul>
<li
v-for="(v, i) in getMenu().filter((x) =>
currentField.format === 'number'
? currentField.formula
? true
: x.code !== 'formula'
: !['filter', 'formula'].find((y) => y === x.code),
)"
:key="i"
:class="selectTab.code === v.code ? 'is-active' : 'has-text-primary'"
@click="changeTab(v)"
>
<a class="py-1.5 fs-14">{{ v.name }}</a>
</li>
</ul>
</div>
<div class="field">
<div v-if="currentTab === 'detail'">
<p class="field fs-14 is-flex is-gap-0.5 is-align-items-center">
<span class="font-semibold">Tên trường:</span>
<span>{{ currentField.name }}</span>
<button
class="button is-small size-8 is-primary is-light rounded-full p-0"
@click="$copyToClipboard(currentField.name)"
>
<span class="icon">
<Icon
name="material-symbols:content-copy-outline-rounded"
:size="16"
/>
</span>
</button>
</p>
<div class="field">
<label class="label fs-14">Định dạng nâng cao</label>
<label class="label fs-14">Mô tả<span class="has-text-danger"> *</span></label>
<div class="control">
<div class="field has-addons">
<div class="control is-expanded">
<input
class="input fs-14 h-full"
type="text"
@change="changeLabel($event.target.value)"
v-model="label"
/>
</div>
<div class="control">
<button
class="button h-full"
@click="editLabel()"
>
<span class="icon">
<Icon
name="material-symbols:edit-outline-rounded"
:size="18"
/>
</span>
</button>
</div>
</div>
</div>
<p
v-if="errors.find((v) => v.name === 'label')"
class="help is-danger"
>
{{ errors.find((v) => v.name === "label").msg }}
</p>
</div>
<div class="field">
<label class="label fs-14">Kiểu dữ liệu<span class="has-text-danger"> * </span></label>
<div class="control is-flex is-gap-0.5">
<button
v-for="(v, i) in colorchoice.filter((v) => v.code !== 'condition')"
v-for="(v, i) in datatype"
:key="i"
@click="changeTemplate(v)"
:class="['button fs-14', radioTemplate === v.code ? 'is-primary is-light' : 'is-white']"
:class="['button fs-14', radioType === v ? 'is-primary is-light' : 'is-white']"
>
<span class="icon">
<Icon
:name="
radioTemplate === v.code
radioType === v
? 'material-symbols:radio-button-checked-outline'
: 'material-symbols:radio-button-unchecked'
"
@@ -390,42 +327,107 @@
</span>
<span>{{ v.name }}</span>
</button>
<button
v-if="radioTemplate === 'option'"
class="button is-primary is-outlined fs-14 ml-2"
@click="showSidebar()"
>
<span class="icon">
<Icon
:name="currentField.template ? 'material-symbols:edit-outline-rounded' : 'material-symbols:add-rounded'"
:size="17"
</div>
</div>
<div
v-if="currentField.format === 'number'"
class="field is-horizontal"
>
<div class="field-body">
<div class="field">
<label class="label fs-14">Đơn vị <span class="has-text-danger"> * </span> </label>
<div class="control">
<SearchBox
v-bind="{
vdata: moneyunit,
field: 'name',
column: ['name'],
first: true,
position: 'is-top-left',
}"
@option="selected('_account', $event)"
/>
</span>
<span>{{ currentField.template ? "Sửa" : "Tạo" }} định dạng</span>
</button>
</div>
<p
class="help has-text-danger"
v-if="errors.find((v) => v.name === 'unit')"
>
{{ errors.find((v) => v.name === "unit").msg }}
</p>
</div>
<div class="field is-narrow">
<label class="label fs-14">Phần thập phân</label>
<div class="control">
<input
class="input"
type="text"
placeholder=""
v-model="decimal"
@input="changeDecimal($event.target.value)"
/>
</div>
</div>
</div>
</div>
<div class="field">
<div class="field">
<label class="label fs-14">Định dạng nâng cao</label>
<div class="control is-flex is-gap-0.5">
<button
v-for="(v, i) in colorchoice.filter((v) => v.code !== 'condition')"
:key="i"
@click="changeTemplate(v)"
:class="['button fs-14', radioTemplate === v.code ? 'is-primary is-light' : 'is-white']"
>
<span class="icon">
<Icon
:name="
radioTemplate === v.code
? 'material-symbols:radio-button-checked-outline'
: 'material-symbols:radio-button-unchecked'
"
:size="22"
/>
</span>
<span>{{ v.name }}</span>
</button>
<button
v-if="radioTemplate === 'option'"
class="button is-primary is-outlined fs-14 ml-2"
@click="showSidebar()"
>
<span class="icon">
<Icon
:name="
currentField.template ? 'material-symbols:edit-outline-rounded' : 'material-symbols:add-rounded'
"
:size="17"
/>
</span>
<span>{{ currentField.template ? "Sửa" : "Tạo" }} định dạng</span>
</button>
</div>
</div>
</div>
</div>
</div>
<div v-else-if="currentTab === 'value'">
<ScrollBox
v-else-if="currentTab === 'value'"
v-bind="{
data: props.filterData,
name: props.field.name,
maxHeight: '380px',
data: filterData,
name: field.name,
perpage: 20,
inContext: true,
}"
@selected="doSelect"
/>
<Modal
v-bind="showmodal"
v-if="showmodal"
@label="changeLabel"
@updatefields="updateFields"
@close="close"
/>
</div>
<Modal
v-bind="showmodal"
v-if="showmodal"
@label="changeLabel"
@updatefields="updateFields"
@close="close"
/>
</template>
<script setup>
import ScrollBox from "~/components/datatable/ScrollBox.vue";