541 lines
17 KiB
Vue
541 lines
17 KiB
Vue
<template>
|
|
<span class="tooltip">
|
|
<a
|
|
class="mr-4"
|
|
@click="checkFilter() ? false : $emit('modalevent', { name: 'dosort', data: 'az' })"
|
|
>
|
|
<SvgIcon
|
|
v-bind="{ name: 'az.svg', type: checkFilter() ? 'grey' : 'primary', size: 22 }"
|
|
></SvgIcon>
|
|
</a>
|
|
<span
|
|
class="tooltiptext"
|
|
style="top: 60%; bottom: unset; min-width: max-content; left: 25px"
|
|
v-html="'Sắp xếp tăng dần'"
|
|
></span>
|
|
</span>
|
|
<span class="tooltip">
|
|
<a
|
|
class="mr-4"
|
|
@click="checkFilter() ? false : $emit('modalevent', { name: 'dosort', data: 'za' })"
|
|
>
|
|
<SvgIcon
|
|
v-bind="{ name: 'az.svg', type: checkFilter() ? 'grey' : 'primary', size: 22 }"
|
|
></SvgIcon>
|
|
</a>
|
|
<span
|
|
class="tooltiptext"
|
|
style="top: 60%; bottom: unset; min-width: max-content; left: 25px"
|
|
>Sắp xếp giảm dần</span
|
|
>
|
|
</span>
|
|
<span class="tooltip">
|
|
<a class="mr-4" @click="moveLeft()">
|
|
<SvgIcon v-bind="{ name: 'left5.png', type: 'primary', size: 22 }"></SvgIcon>
|
|
</a>
|
|
<span
|
|
class="tooltiptext"
|
|
style="top: 60%; bottom: unset; min-width: max-content; left: 25px"
|
|
>Chuyển cột sang trái</span
|
|
>
|
|
</span>
|
|
<span class="tooltip">
|
|
<a class="mr-4" @click="moveRight()">
|
|
<SvgIcon v-bind="{ name: 'right5.png', type: 'primary', size: 22 }"></SvgIcon>
|
|
</a>
|
|
<span
|
|
class="tooltiptext"
|
|
style="top: 60%; bottom: unset; min-width: max-content; left: 25px"
|
|
>Chuyển cột sang phải</span
|
|
>
|
|
</span>
|
|
<span class="tooltip">
|
|
<a class="mr-4" @click="resizeWidth()">
|
|
<SvgIcon v-bind="{ name: 'thick.svg', type: 'primary', size: 22 }"></SvgIcon>
|
|
</a>
|
|
<span
|
|
class="tooltiptext"
|
|
style="top: 60%; bottom: unset; min-width: max-content; left: 25px"
|
|
>Tăng độ rộng cột</span
|
|
>
|
|
</span>
|
|
<span class="tooltip">
|
|
<a class="mr-4" @click="resizeWidth(true)">
|
|
<SvgIcon v-bind="{ name: 'thin.svg', type: 'primary', size: 23 }"></SvgIcon>
|
|
</a>
|
|
<span
|
|
class="tooltiptext"
|
|
style="top: 60%; bottom: unset; min-width: max-content; left: 25px"
|
|
>Giảm độ rộng cột</span
|
|
>
|
|
</span>
|
|
<span class="tooltip">
|
|
<a class="mr-4" @click="hideField()">
|
|
<SvgIcon v-bind="{ name: 'eye-off.svg', type: 'primary', size: 23 }"></SvgIcon>
|
|
</a>
|
|
<span
|
|
class="tooltiptext"
|
|
style="top: 60%; bottom: unset; min-width: max-content; left: 25px"
|
|
>Ẩn cột</span
|
|
>
|
|
</span>
|
|
<!-- <template v-if="store.login ? store.login.is_admin : false"> -->
|
|
<span class="tooltip">
|
|
<a class="mr-4" @click="currentField.mandatory ? false : doRemove()">
|
|
<SvgIcon v-bind="{ name: 'bin.svg', type: 'primary', size: 23 }"></SvgIcon>
|
|
</a>
|
|
<span
|
|
class="tooltiptext"
|
|
style="top: 60%; bottom: unset; min-width: max-content; left: 25px"
|
|
>Xóa cột</span
|
|
>
|
|
</span>
|
|
<span class="tooltip">
|
|
<a
|
|
class="mr-4"
|
|
:class="currentField.format === 'number' ? null : 'has-text-grey-light'"
|
|
@click="
|
|
currentField.format === 'number'
|
|
? $emit('modalevent', { name: 'copyfield', data: currentField })
|
|
: false
|
|
"
|
|
>
|
|
<SvgIcon v-bind="{ name: 'copy.svg', type: 'primary', size: 22 }"></SvgIcon>
|
|
</a>
|
|
<span
|
|
class="tooltiptext"
|
|
style="top: 60%; bottom: unset; min-width: max-content; left: 25px"
|
|
>Sao chép cột</span
|
|
>
|
|
</span>
|
|
<span class="tooltip">
|
|
<a class="mr-4" @click="fieldList()">
|
|
<SvgIcon v-bind="{ name: 'menu4.png', type: 'primary', size: 22 }"></SvgIcon>
|
|
</a>
|
|
<span
|
|
class="tooltiptext"
|
|
style="top: 60%; bottom: unset; min-width: max-content; left: 25px"
|
|
>Danh sách cột</span
|
|
>
|
|
</span>
|
|
<span class="tooltip">
|
|
<a class="mr-4" @click="createField()">
|
|
<SvgIcon v-bind="{ name: 'add.png', type: 'primary', size: 22 }"></SvgIcon>
|
|
</a>
|
|
<span
|
|
class="tooltiptext"
|
|
style="top: 60%; bottom: unset; min-width: max-content; left: 25px"
|
|
>Tạo cột mới</span
|
|
>
|
|
</span>
|
|
<span class="tooltip">
|
|
<a class="mr-4" @click="tableOption()">
|
|
<SvgIcon v-bind="{ name: 'more.svg', type: 'primary', size: 22 }"></SvgIcon>
|
|
</a>
|
|
<span
|
|
class="tooltiptext"
|
|
style="top: 60%; bottom: unset; min-width: max-content; left: 25px"
|
|
>Tùy chọn bảng</span
|
|
>
|
|
</span>
|
|
<span class="tooltip">
|
|
<a class="mr-4" @click="saveSetting()">
|
|
<SvgIcon v-bind="{ name: 'save.svg', type: 'primary', size: 22 }"></SvgIcon>
|
|
</a>
|
|
<span
|
|
class="tooltiptext"
|
|
style="top: 60%; bottom: unset; min-width: max-content; left: 25px"
|
|
>Lưu thiết lập</span
|
|
>
|
|
</span>
|
|
<!-- </template> -->
|
|
<div class="panel-tabs mb-2">
|
|
<a
|
|
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)"
|
|
>
|
|
{{ v.name }}
|
|
</a>
|
|
</div>
|
|
<div v-if="currentTab === 'detail'">
|
|
<p class="fs-14 mt-3">
|
|
<strong> Tên trường: </strong> {{ currentField.name }}
|
|
<a @click="copyContent(currentField.name)">
|
|
<span class="tooltip">
|
|
<SvgIcon
|
|
class="ml-1"
|
|
v-bind="{ name: 'copy.svg', type: 'primary', size: 16 }"
|
|
></SvgIcon>
|
|
<span
|
|
class="tooltiptext"
|
|
style="top: 60%; bottom: unset; min-width: max-content; left: 25px"
|
|
>Copy</span
|
|
>
|
|
</span>
|
|
</a>
|
|
</p>
|
|
<label class="label fs-14 mt-3">Mô tả<span class="has-text-danger"> *</span></label>
|
|
<div class="field has-addons">
|
|
<div class="control is-expanded">
|
|
<input
|
|
class="input fs-14"
|
|
type="text"
|
|
@change="changeLabel($event.target.value)"
|
|
v-model="label"
|
|
/>
|
|
</div>
|
|
<div class="control">
|
|
<button class="button" @click="editLabel()">
|
|
<SvgIcon v-bind="{ name: 'pen.svg', type: 'dark', size: 19 }"></SvgIcon>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<p class="help is-danger" v-if="errors.find((v) => v.name === 'label')">
|
|
{{ errors.find((v) => v.name === "label").msg }}
|
|
</p>
|
|
<div class="field mt-3">
|
|
<label class="label fs-14"
|
|
>Kiểu dữ liệu<span class="has-text-danger"> * </span></label
|
|
>
|
|
<div class="control fs-14">
|
|
<span class="mr-4" v-for="(v, i) in datatype">
|
|
<span class="icon-text" v-if="radioType === v">
|
|
<SvgIcon
|
|
v-bind="{ name: 'radio-checked.svg', type: 'gray', size: 22 }"
|
|
></SvgIcon>
|
|
</span>
|
|
{{ v.name }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="field is-horizontal" v-if="currentField.format === 'number'">
|
|
<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)"
|
|
></SearchBox>
|
|
</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 is-horizontal mt-3">
|
|
<div class="field-body">
|
|
<div class="field">
|
|
<label class="label fs-14">Định dạng nâng cao</label>
|
|
<p class="control fs-14">
|
|
<span
|
|
class="mr-4"
|
|
v-for="(v, i) in colorchoice.filter((v) => v.code !== 'condition')"
|
|
>
|
|
<a class="icon-text" @click="changeTemplate(v)">
|
|
<SvgIcon
|
|
v-bind="{
|
|
name: `radio-${radioTemplate === v.code ? '' : 'un'}checked.svg`,
|
|
type: 'gray',
|
|
size: 22,
|
|
}"
|
|
>
|
|
</SvgIcon>
|
|
</a>
|
|
{{ v.name }}
|
|
</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<p class="mt-3" v-if="radioTemplate === 'option'">
|
|
<button class="button is-primary is-small has-text-white" @click="showSidebar()">
|
|
<span class="fs-14">{{
|
|
`${currentField.template ? "Sửa" : "Tạo"} định dạng`
|
|
}}</span>
|
|
</button>
|
|
</p>
|
|
</div>
|
|
<div v-else-if="currentTab === 'value'">
|
|
<ScrollBox
|
|
v-bind="{
|
|
data: props.filterData,
|
|
name: props.field.name,
|
|
maxheight: '380px',
|
|
perpage: 20,
|
|
}"
|
|
@selected="doSelect"
|
|
/>
|
|
</div>
|
|
<Modal
|
|
v-bind="showmodal"
|
|
v-if="showmodal"
|
|
@label="changeLabel"
|
|
@updatefields="updateFields"
|
|
@close="close"
|
|
></Modal>
|
|
</template>
|
|
<script setup>
|
|
import { useStore } from "@/stores/index";
|
|
import ScrollBox from "~/components/datatable/ScrollBox";
|
|
const store = useStore();
|
|
const {
|
|
$copy,
|
|
$stripHtml,
|
|
$clone,
|
|
$arrayMove,
|
|
$snackbar,
|
|
$copyToClipboard,
|
|
} = useNuxtApp();
|
|
var props = defineProps({
|
|
pagename: String,
|
|
field: Object,
|
|
filters: Object,
|
|
filterData: Object,
|
|
width: String,
|
|
});
|
|
const emit = defineEmits(["modalevent", "changepos", "close"]);
|
|
var colorchoice = store.colorchoice;
|
|
var errors = [];
|
|
var currentTab = ref("value");
|
|
var currentField = $copy(props.field);
|
|
var pagedata = store[props.pagename];
|
|
var fields = [];
|
|
var label = currentField.label;
|
|
var showmodal = ref();
|
|
const checkFilter = function () {};
|
|
const getMenu = function () {
|
|
let field = currentField;
|
|
field.disable = "display,tooltip";
|
|
let arr = field.disable ? field.disable.split(",") : undefined;
|
|
let array = arr
|
|
? store.menuchoice.filter((v) => arr.findIndex((x) => x === v.code) < 0)
|
|
: store.menuchoice;
|
|
//if (store.login ? !(store.login.is_admin === false) : true) array = [array[0]];
|
|
return array;
|
|
};
|
|
var selectTab = getMenu()[0];
|
|
var datatype = store.datatype;
|
|
var current = 1;
|
|
var value1 = undefined;
|
|
var value2 = undefined;
|
|
var moneyunit = store.moneyunit;
|
|
var radioType = store.datatype.find((v) => v.code === currentField.format);
|
|
var selectUnit =
|
|
currentField.format === "number"
|
|
? moneyunit.find((v) => v.detail === currentField.unit)
|
|
: undefined;
|
|
var bgcolor = undefined;
|
|
var radioBGcolor = colorchoice.find((v) => v.code === "none");
|
|
var color = undefined;
|
|
var radioColor = colorchoice.find((v) => v.code === "none");
|
|
var textsize = undefined;
|
|
var radioSize = colorchoice.find((v) => v.code === "none");
|
|
var minwidth = undefined;
|
|
var radioWidth = colorchoice.find((v) => v.code === "none");
|
|
var radioMaxWidth = colorchoice.find((v) => v.code === "none");
|
|
var maxwidth = undefined;
|
|
var selectAlign = undefined;
|
|
var radioAlign = colorchoice.find((v) => v.code === "none");
|
|
var radioTemplate = ref(
|
|
colorchoice.find((v) => v.code === (currentField.template ? "option" : "none"))["code"]
|
|
);
|
|
var selectPlacement = store.placement.find((v) => v.code === "is-right");
|
|
var selectScheme = store.colorscheme.find((v) => v.code === "is-primary");
|
|
var radioTooltip = store.colorchoice.find((v) => v.code === "none");
|
|
var selectField = undefined;
|
|
var tags = currentField.tags
|
|
? currentField.tags.map((v) => fields.find((x) => x.name === v))
|
|
: [];
|
|
var formula = currentField.formula ? currentField.formula : undefined;
|
|
var decimal = currentField.decimal;
|
|
let shortmenu = store.menuchoice.filter((x) =>
|
|
currentField.format === "number"
|
|
? currentField.formula
|
|
? true
|
|
: x.code !== "formula"
|
|
: !["filter", "formula"].find((y) => y === x.code)
|
|
);
|
|
var selectTab = shortmenu.find((v) => selectTab.code === v.code)
|
|
? selectTab
|
|
: menuchoice.find((v) => v.code === "value");
|
|
var search = undefined;
|
|
// if(selectTab.code==='value') {
|
|
// let self = this
|
|
// setTimeout(function() {self.$refs[currentField.name]? self.$refs[currentField.name].focus() : false}, 50)
|
|
// }
|
|
//==============================================================
|
|
function moveLeft() {
|
|
let copy = $clone(pagedata);
|
|
let i = copy.fields.findIndex((v) => v.name === props.field.name);
|
|
let idx = i - 1 >= 0 ? i - 1 : copy.fields.length - 1;
|
|
$arrayMove(copy.fields, i, idx);
|
|
copy.update = { fields: copy.fields };
|
|
store.commit(props.pagename, copy);
|
|
emit("changepos");
|
|
}
|
|
function moveRight() {
|
|
let copy = $clone(pagedata);
|
|
let i = copy.fields.findIndex((v) => v.name === props.field.name);
|
|
let idx = copy.fields.length - 1 > i ? i + 1 : 0;
|
|
$arrayMove(copy.fields, i, idx);
|
|
copy.update = { fields: copy.fields };
|
|
store.commit(props.pagename, copy);
|
|
emit("changepos");
|
|
}
|
|
function hideField() {
|
|
let copy = $clone(store[props.pagename]);
|
|
let found = copy.fields.find((v) => v.name === props.field.name);
|
|
found.show = false;
|
|
copy.update = { fields: copy.fields };
|
|
store.commit(props.pagename, copy);
|
|
emit("close");
|
|
}
|
|
function doRemove() {
|
|
let copy = $clone(store[props.pagename]);
|
|
let idx = copy.fields.findIndex((v) => v.name === props.field.name);
|
|
copy.fields.splice(idx, 1);
|
|
copy.update = { fields: copy.fields };
|
|
store.commit(props.pagename, copy);
|
|
emit("close");
|
|
}
|
|
function fieldList() {
|
|
showmodal.value = {
|
|
component: "datatable/TableOption",
|
|
vbind: { pagename: props.pagename },
|
|
title: "Danh sách cột",
|
|
width: "50%",
|
|
height: "630px",
|
|
};
|
|
}
|
|
function tableOption() {
|
|
showmodal.value = {
|
|
component: "datatable/TableSetting",
|
|
vbind: { pagename: props.pagename },
|
|
title: "Tùy chọn bảng",
|
|
width: "40%",
|
|
height: "400px",
|
|
};
|
|
}
|
|
const getFields = function () {
|
|
fields = pagedata ? $copy(pagedata.fields) : [];
|
|
fields.map(
|
|
(v) => (v.caption = (v.label ? v.label.indexOf("<") >= 0 : false) ? v.name : v.label)
|
|
);
|
|
};
|
|
const doSelect = function (evt) {
|
|
emit("modalevent", { name: "selected", data: evt[props.field.name] });
|
|
};
|
|
const changeLabel = function (text) {
|
|
currentField.label = text;
|
|
updateFields(currentField);
|
|
};
|
|
function editLabel() {
|
|
showmodal.value = {
|
|
component: "datatable/EditLabel",
|
|
width: "500px",
|
|
height: "300px",
|
|
vbind: { label: label },
|
|
};
|
|
}
|
|
const changeTemplate = function (v) {
|
|
radioTemplate.value = v.code;
|
|
let copy = $copy(currentField);
|
|
copy.template = v.code;
|
|
updateFields(copy);
|
|
};
|
|
function createField() {
|
|
showmodal.value = {
|
|
component: "datatable/NewField",
|
|
vbind: { pagename: props.pagename },
|
|
title: "Tạo cột mới",
|
|
width: "50%",
|
|
height: "630px",
|
|
};
|
|
}
|
|
function copyContent(value) {
|
|
$copyToClipboard(value);
|
|
}
|
|
function close() {
|
|
showmodal.value = undefined;
|
|
}
|
|
const updateFields = function (field, type) {
|
|
let copy = $clone(store[props.pagename]);
|
|
let idx = copy.fields.findIndex((v) => v.name === field.name);
|
|
copy.fields[idx] = field;
|
|
store.commit(props.pagename, copy);
|
|
};
|
|
const changeTab = function (v) {
|
|
currentTab.value = v.code;
|
|
selectTab = v;
|
|
};
|
|
const saveSetting = function () {
|
|
showmodal.value = {
|
|
component: "datatable/MenuSave",
|
|
vbind: { pagename: props.pagename, classify: 4 },
|
|
title: "Lưu thiết lập",
|
|
width: "500px",
|
|
height: "400px",
|
|
};
|
|
};
|
|
const showSidebar = function () {
|
|
let event = { name: "template", field: currentField };
|
|
let title = "Danh sách cột";
|
|
if (event.name === "bgcolor")
|
|
title = `Đổi màu nền: ${event.field.name} / ${$stripHtml(event.field.label, 30)}`;
|
|
else if (event.name === "color")
|
|
title = `Đổi màu chữ: ${event.field.name} / ${$stripHtml(event.field.label, 30)}`;
|
|
else if (event.name === "template")
|
|
title = `Định dạng nâng cao: ${$stripHtml(event.field.label, 30)}`;
|
|
showmodal.value = {
|
|
component: "datatable/FormatOption",
|
|
vbind: { event: event, currentField: currentField, pagename: props.pagename },
|
|
width: "850px",
|
|
height: "700px",
|
|
title: title,
|
|
};
|
|
};
|
|
function resizeWidth(minus) {
|
|
let val = maxwidth || minwidth || 80;
|
|
val = minus ? parseInt(val - 0.1 * val) : parseInt(val + 0.1 * val);
|
|
if (val > 1000) return $snackbar("Độ rộng cột lớn hơn giới hạn cho phép");
|
|
else if (val < 20) return $snackbar("Độ rộng cột nhỏ hơn giới hạn cho phép");
|
|
radioMaxWidth = store.colorchoice.find((v) => v.code === "option");
|
|
radioWidth = store.colorchoice.find((v) => v.code === "option");
|
|
maxwidth = val;
|
|
currentField.maxwidth = val;
|
|
minwidth = val;
|
|
currentField.minwidth = val;
|
|
updateFields(currentField);
|
|
}
|
|
</script>
|