changes
This commit is contained in:
540
components/datatable/ContextMenu.vue
Normal file
540
components/datatable/ContextMenu.vue
Normal file
@@ -0,0 +1,540 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user