chore: install prettier

This commit is contained in:
Viet An
2026-05-04 15:22:27 +07:00
parent 93d29ca7d8
commit bd58e2b847
267 changed files with 22950 additions and 13581 deletions

View File

@@ -1,49 +1,110 @@
<template>
<div>
<div class="field has-addons" :id="docid">
<div
class="field has-addons"
:id="docid"
>
<div class="control has-icons-left is-expanded">
<div :class="`dropdown ${ pos || ''} ${focused? 'is-active' : ''}`" style="width: 100%;">
<div class="dropdown-trigger" style="width: 100%;">
<input
:disabled="disabled"
:class="`input ${error? 'is-danger' : ''} ${disabled? 'has-text-dark' : ''}`"
type="text"
@focus="setFocus"
@blur="lostFocus"
@keyup.enter="pressEnter"
@keyup="beginSearch"
<div
:class="`dropdown ${pos || ''} ${focused ? 'is-active' : ''}`"
style="width: 100%"
>
<div
class="dropdown-trigger"
style="width: 100%"
>
<input
:disabled="disabled"
:class="`input ${error ? 'is-danger' : ''} ${disabled ? 'has-text-dark' : ''}`"
type="text"
@focus="setFocus"
@blur="lostFocus"
@keyup.enter="pressEnter"
@keyup="beginSearch"
v-model="value"
:placeholder="placeholder"
/>
</div>
<div class="dropdown-menu" style="min-width: 100%" role="menu" @click="doClick()">
<div class="dropdown-content px-3" style="min-width: 100%;">
<p class="has-text-warning" v-if="data.length===0">{{ isVietnamese ? 'Không giá trị thỏa mãn' : 'No matching values' }}</p>
<ScrollBox v-bind="{data: data, name: field, fontsize: 14, maxheight: '200px', notick: true}" @selected="choose" v-else></ScrollBox>
<div
class="dropdown-menu"
style="min-width: 100%"
role="menu"
@click="doClick()"
>
<div
class="dropdown-content px-3"
style="min-width: 100%"
>
<p
class="has-text-warning"
v-if="data.length === 0"
>
{{ isVietnamese ? "Không có giá trị thỏa mãn" : "No matching values" }}
</p>
<ScrollBox
v-bind="{
data: data,
name: field,
fontsize: 14,
maxheight: '200px',
notick: true,
}"
@selected="choose"
v-else
></ScrollBox>
</div>
</div>
</div>
<span class="icon is-left">
<SvgIcon v-bind="{name: 'magnify.svg', type: 'gray', size: 22}"></SvgIcon>
<SvgIcon v-bind="{ name: 'magnify.svg', type: 'gray', size: 22 }"></SvgIcon>
</span>
</div>
<div class="control" v-if="clearable && value">
<button class="button is-primary px-2" @click="clearValue" style="height: 100%" type="button">
<SvgIcon v-bind="{name: 'close.svg', type: 'white', size: 24}"></SvgIcon>
<div
class="control"
v-if="clearable && value"
>
<button
class="button is-primary px-2"
@click="clearValue"
style="height: 100%"
type="button"
>
<SvgIcon v-bind="{ name: 'close.svg', type: 'white', size: 24 }"></SvgIcon>
</button>
</div>
<div class="control" v-if="viewaddon">
<button class="button is-dark px-2" @click="viewInfo()" style="height: 100%" type="button">
<SvgIcon v-bind="{name: 'view.svg', type: 'white', size: 24}"></SvgIcon>
<div
class="control"
v-if="viewaddon"
>
<button
class="button is-dark px-2"
@click="viewInfo()"
style="height: 100%"
type="button"
>
<SvgIcon v-bind="{ name: 'view.svg', type: 'white', size: 24 }"></SvgIcon>
</button>
</div>
<div class="control" v-if="addon">
<button class="button is-primary px-2" @click="addNew()" style="height: 100%" type="button">
<SvgIcon v-bind="{name: 'add1.png', type: 'white', size: 24}"></SvgIcon>
<div
class="control"
v-if="addon"
>
<button
class="button is-primary px-2"
@click="addNew()"
style="height: 100%"
type="button"
>
<SvgIcon v-bind="{ name: 'add1.png', type: 'white', size: 24 }"></SvgIcon>
</button>
</div>
</div>
<Modal @dataevent="dataevent" @close="showmodal=undefined" v-bind="showmodal" v-if="showmodal"></Modal>
<Modal
@dataevent="dataevent"
@close="showmodal = undefined"
v-bind="showmodal"
v-if="showmodal"
></Modal>
</div>
</template>
@@ -51,7 +112,22 @@
import { useStore } from "@/stores/index";
export default {
props: ['api', 'field', 'column', 'first', 'optionid', 'filter', 'addon', 'viewaddon', 'position', 'disabled', 'vdata', 'clearable', 'placeholder', 'searchfield'],
props: [
"api",
"field",
"column",
"first",
"optionid",
"filter",
"addon",
"viewaddon",
"position",
"disabled",
"vdata",
"clearable",
"placeholder",
"searchfield",
],
setup() {
const store = useStore();
return { store };
@@ -64,7 +140,7 @@ export default {
value: undefined,
selected: undefined,
showmodal: undefined,
params: this.api? this.$findapi(this.api)['params'] : undefined,
params: this.api ? this.$findapi(this.api)["params"] : undefined,
orgdata: undefined,
error: false,
focused: false,
@@ -72,142 +148,142 @@ export default {
count2: 0,
docid: this.$id(),
pos: undefined,
}
};
},
computed: {
isVietnamese() {
return this.store.lang === "vi";
}
},
},
async created() {
this.getPos()
if(this.vdata) {
this.orgdata = this.$copy(this.vdata)
this.orgdata.map(v=>v.search = this.$nonAccent(v[this.field]))
this.getPos();
if (this.vdata) {
this.orgdata = this.$copy(this.vdata);
this.orgdata.map((v) => (v.search = this.$nonAccent(v[this.field])));
}
if(this.first) {
this.data = this.orgdata? this.$copy(this.orgdata) : await this.getData()
if(this.optionid) {
let f = {}
f[this.field] = this.optionid
if(this.optionid>0) f = {id: this.optionid}
this.selected = this.$find(this.data, f)
if(this.selected && this.vdata) {
return this.value = this.selected[this.field]
if (this.first) {
this.data = this.orgdata ? this.$copy(this.orgdata) : await this.getData();
if (this.optionid) {
let f = {};
f[this.field] = this.optionid;
if (this.optionid > 0) f = { id: this.optionid };
this.selected = this.$find(this.data, f);
if (this.selected && this.vdata) {
return (this.value = this.selected[this.field]);
}
}
} else if(this.optionid) {
this.selected = await this.$getdata(this.api, {id: this.optionid}, undefined, true)
} else if (this.optionid) {
this.selected = await this.$getdata(this.api, { id: this.optionid }, undefined, true);
}
if(this.selected) this.doSelect(this.selected)
if (this.selected) this.doSelect(this.selected);
},
watch: {
optionid: function(newVal) {
if(this.optionid) this.selected = this.$find(this.data, {id: this.optionid})
if(this.selected) this.doSelect(this.selected)
else this.value = undefined
optionid: function (newVal) {
if (this.optionid) this.selected = this.$find(this.data, { id: this.optionid });
if (this.selected) this.doSelect(this.selected);
else this.value = undefined;
},
filter: async function(newVal) {
this.data = await this.getData()
filter: async function (newVal) {
this.data = await this.getData();
},
vdata: function(newval) {
if(newval) {
this.orgdata = this.$copy(this.vdata)
this.orgdata.map(v=>v.search = this.$nonAccent(v[this.field]))
this.data = this.$copy(this.orgdata)
this.selected = undefined
this.value = undefined
if(this.optionid) this.selected = this.$find(this.data, {id: this.optionid})
if(this.selected) this.doSelect(this.selected)
vdata: function (newval) {
if (newval) {
this.orgdata = this.$copy(this.vdata);
this.orgdata.map((v) => (v.search = this.$nonAccent(v[this.field])));
this.data = this.$copy(this.orgdata);
this.selected = undefined;
this.value = undefined;
if (this.optionid) this.selected = this.$find(this.data, { id: this.optionid });
if (this.selected) this.doSelect(this.selected);
}
}
},
},
methods: {
choose(v) {
this.focused = false
this.count1 = 0
this.count2 = 0
this.doSelect(v)
this.focused = false;
this.count1 = 0;
this.count2 = 0;
this.doSelect(v);
},
setFocus() {
this.focused = true
this.count1 = 0
this.count2 = 0
this.focused = true;
this.count1 = 0;
this.count2 = 0;
},
lostFocus() {
let self = this
setTimeout(()=>{
if(self.focused && self.count1===0) self.focused = false
}, 200)
let self = this;
setTimeout(() => {
if (self.focused && self.count1 === 0) self.focused = false;
}, 200);
},
pressEnter() {
if(this.data.length===0) return
this.choose(this.data[0])
if (this.data.length === 0) return;
this.choose(this.data[0]);
},
doClick() {
this.count1 += 1
this.count1 += 1;
},
doSelect(option) {
if(this.$empty(option)) return
this.$emit('option', option)
this.$emit('modalevent', {name: 'option', data: option})
this.selected = option
this.value = this.selected[this.field]
if (this.$empty(option)) return;
this.$emit("option", option);
this.$emit("modalevent", { name: "option", data: option });
this.selected = option;
this.value = this.selected[this.field];
},
clearValue() {
this.value = undefined
this.selected = undefined
this.$emit('option', null)
this.$emit('modalevent', {name: 'option', data: null})
this.value = undefined;
this.selected = undefined;
this.$emit("option", null);
this.$emit("modalevent", { name: "option", data: null });
},
findObject(val) {
let rows = this.$copy(this.orgdata)
if(this.$empty(val)) this.data = rows
let rows = this.$copy(this.orgdata);
if (this.$empty(val)) this.data = rows;
else {
let text = this.$nonAccent(val)
this.data = rows.filter(v=>v.search.toLowerCase().indexOf(text.toLowerCase())>=0)
let text = this.$nonAccent(val);
this.data = rows.filter((v) => v.search.toLowerCase().indexOf(text.toLowerCase()) >= 0);
}
},
async getData() {
this.params.filter = this.filter
let data = await this.$getdata(this.api, undefined, this.params)
return data
this.params.filter = this.filter;
let data = await this.$getdata(this.api, undefined, this.params);
return data;
},
async getApi(val) {
if(this.vdata) return this.findObject(val)
let text = val? val.toLowerCase() : ''
let f = {}
if (this.vdata) return this.findObject(val);
let text = val ? val.toLowerCase() : "";
let f = {};
// Sử dụng searchfield nếu có, nếu không thì dùng column
const fieldsToSearch = this.searchfield || this.column;
fieldsToSearch.map(v=>{
f[`${v}__icontains`] = text
})
this.params.filter_or = f
if(this.filter) this.params.filter = this.$copy(this.filter)
let arr = await this.$getdata(this.api, undefined, this.params)
this.data = this.$copy(arr)
fieldsToSearch.map((v) => {
f[`${v}__icontains`] = text;
});
this.params.filter_or = f;
if (this.filter) this.params.filter = this.$copy(this.filter);
let arr = await this.$getdata(this.api, undefined, this.params);
this.data = this.$copy(arr);
},
beginSearch(e) {
let val = e.target.value
this.search = val
if (this.timer) clearTimeout(this.timer)
this.timer = setTimeout(() => this.getApi(val), 150)
let val = e.target.value;
this.search = val;
if (this.timer) clearTimeout(this.timer);
this.timer = setTimeout(() => this.getApi(val), 150);
},
addNew() {
this.showmodal = this.$copy(this.addon)
this.showmodal = this.$copy(this.addon);
},
dataevent(v) {
console.log("SearchBox received dataevent:", v); // Debug log
if (!v || !v.id) {
console.error("Invalid data received in SearchBox:", v);
return;
}
// Tìm và cập nhật trong danh sách
let idx = this.$findIndex(this.data, {id: v.id})
let idx = this.$findIndex(this.data, { id: v.id });
if (idx < 0) {
// Nếu chưa có trong danh sách, thêm vào đầu
this.data.unshift(v);
@@ -217,10 +293,10 @@ export default {
this.data[idx] = v;
console.log("Updated existing item in data:", v);
}
// Cập nhật orgdata nếu có
if (this.orgdata) {
let orgIdx = this.$findIndex(this.orgdata, {id: v.id});
let orgIdx = this.$findIndex(this.orgdata, { id: v.id });
if (orgIdx < 0) {
this.orgdata.unshift(v);
// Thêm search field cho orgdata
@@ -234,42 +310,46 @@ export default {
}
}
}
// **Tự động select item vừa tạo/cập nhật**
this.doSelect(v);
// Đóng modal
this.showmodal = undefined;
console.log("SearchBox data after update:", this.data);
},
viewInfo() {
if(!this.selected) return this.$dialog(this.isVietnamese ? 'Vui lòng lựa chọn trước khi xem thông tin.' : 'Please select before viewing', this.isVietnamese ? 'Thông báo' : 'Notice')
let copy = this.$copy(this.viewaddon)
copy.vbind = {row: this.selected}
this.showmodal = copy
if (!this.selected)
return this.$dialog(
this.isVietnamese ? "Vui lòng lựa chọn trước khi xem thông tin." : "Please select before viewing",
this.isVietnamese ? "Thông báo" : "Notice",
);
let copy = this.$copy(this.viewaddon);
copy.vbind = { row: this.selected };
this.showmodal = copy;
},
getPos() {
switch(this.position) {
case 'is-top-left':
this.pos = 'is-up is-left'
switch (this.position) {
case "is-top-left":
this.pos = "is-up is-left";
break;
case 'is-top-right':
this.pos = 'is-up is-right'
case "is-top-right":
this.pos = "is-up is-right";
break;
case 'is-bottom-left':
this.pos = 'is-right'
case "is-bottom-left":
this.pos = "is-right";
break;
case 'is-bottom-right':
this.pos = 'is-right'
case "is-bottom-right":
this.pos = "is-right";
break;
}
}
}
}
},
},
};
</script>
<style scoped>
.field:not(:last-child) {
margin-bottom: 0;
}
</style>
</style>