changes
This commit is contained in:
@@ -143,176 +143,182 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useStore } from "@/stores/index";
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
api: String,
|
||||
field: String,
|
||||
column: Array,
|
||||
first: Boolean,
|
||||
optionid: String,
|
||||
filter: Object,
|
||||
addon: Object,
|
||||
viewaddon: Object,
|
||||
position: String,
|
||||
disabled: Boolean,
|
||||
vdata: Array,
|
||||
clearable: Boolean,
|
||||
placeholder: String,
|
||||
searchfield: Array,
|
||||
});
|
||||
const { $copy, $dialog, $empty, $find, $findapi, $findIndex, $getdata, $id, $nonAccent, $store } = useNuxtApp();
|
||||
const emit = defineEmits(["option", "modalevent"]);
|
||||
const search = ref();
|
||||
const data = ref([]);
|
||||
const isLoading = ref(false);
|
||||
const timer = ref();
|
||||
const value = ref();
|
||||
const selected = ref();
|
||||
const showmodal = ref();
|
||||
const params = ref(props.api && $findapi(props.api).params);
|
||||
const orgdata = ref();
|
||||
const error = ref(false);
|
||||
const focused = ref(false);
|
||||
const count1 = ref(0);
|
||||
const count2 = ref(0);
|
||||
const docid = ref($id());
|
||||
const pos = ref();
|
||||
|
||||
export default {
|
||||
props: [
|
||||
"api",
|
||||
"field",
|
||||
"column",
|
||||
"first",
|
||||
"optionid",
|
||||
"filter",
|
||||
"addon",
|
||||
"viewaddon",
|
||||
"position",
|
||||
"disabled",
|
||||
"vdata",
|
||||
"clearable",
|
||||
"placeholder",
|
||||
"searchfield",
|
||||
],
|
||||
setup() {
|
||||
const store = useStore();
|
||||
return { store };
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
search: undefined,
|
||||
data: [],
|
||||
isLoading: false,
|
||||
timer: undefined,
|
||||
value: undefined,
|
||||
selected: undefined,
|
||||
showmodal: undefined,
|
||||
params: this.api ? this.$findapi(this.api)["params"] : undefined,
|
||||
orgdata: undefined,
|
||||
error: false,
|
||||
focused: false,
|
||||
count1: 0,
|
||||
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])));
|
||||
}
|
||||
if (this.first) {
|
||||
this.data = this.orgdata ? this.$copy(this.orgdata) : await this.getData();
|
||||
if (this.optionid) {
|
||||
getPos();
|
||||
|
||||
if (props.vdata) {
|
||||
orgdata.value = props.vdata;
|
||||
orgdata.value.forEach((v) => (v.search = $nonAccent(v[props.field])));
|
||||
}
|
||||
if (props.first) {
|
||||
data.value = orgdata.value ? $copy(orgdata.value) : await getData();
|
||||
if (props.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]);
|
||||
f[props.field] = props.optionid;
|
||||
if (props.optionid > 0) f = { id: props.optionid };
|
||||
selected.value = $find(data.value, f);
|
||||
if (selected.value && props.vdata) {
|
||||
value.value = selected.value[props.field];
|
||||
}
|
||||
}
|
||||
} else if (this.optionid) {
|
||||
this.selected = await this.$getdata(this.api, { id: this.optionid }, undefined, true);
|
||||
}
|
||||
if (this.selected) this.doSelect(this.selected);
|
||||
} else if (props.optionid) {
|
||||
selected.value = await $getdata(props.api, { id: props.optionid }, undefined, true);
|
||||
}
|
||||
if (selected.value) doSelect(selected.value);
|
||||
|
||||
watch(
|
||||
() => props.optionid,
|
||||
() => {
|
||||
if (props.optionid) selected.value = $find(data.value, { id: props.optionid });
|
||||
if (selected.value) doSelect(selected.value);
|
||||
else value.value = undefined;
|
||||
},
|
||||
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;
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.filter,
|
||||
async () => {
|
||||
data.value = await 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);
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.vdata,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
orgdata.value = $copy(props.vdata);
|
||||
orgdata.value.forEach((v) => (v.search = $nonAccent(v[props.field])));
|
||||
data.value = $copy(orgdata.value);
|
||||
selected.value = undefined;
|
||||
value.value = undefined;
|
||||
if (props.optionid) selected.value = $find(data.value, { id: props.optionid });
|
||||
if (selected.value) doSelect(selected.value);
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
choose(v) {
|
||||
this.focused = false;
|
||||
this.count1 = 0;
|
||||
this.count2 = 0;
|
||||
this.doSelect(v);
|
||||
},
|
||||
setFocus() {
|
||||
this.focused = true;
|
||||
this.count1 = 0;
|
||||
this.count2 = 0;
|
||||
},
|
||||
lostFocus() {
|
||||
let self = this;
|
||||
);
|
||||
|
||||
function choose(v) {
|
||||
focused.value = false;
|
||||
count1.value = 0;
|
||||
count2.value = 0;
|
||||
doSelect(v);
|
||||
}
|
||||
|
||||
function setFocus() {
|
||||
focused.value = true;
|
||||
count1.value = 0;
|
||||
count2.value = 0;
|
||||
}
|
||||
|
||||
function lostFocus() {
|
||||
setTimeout(() => {
|
||||
if (self.focused && self.count1 === 0) self.focused = false;
|
||||
if (focused.value && count1.value === 0) focused.value = false;
|
||||
}, 200);
|
||||
},
|
||||
pressEnter() {
|
||||
if (this.data.length === 0) return;
|
||||
this.choose(this.data[0]);
|
||||
},
|
||||
doClick() {
|
||||
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];
|
||||
},
|
||||
clearValue() {
|
||||
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;
|
||||
}
|
||||
|
||||
function pressEnter() {
|
||||
if (data.value.length === 0) return;
|
||||
choose(data.value[0]);
|
||||
}
|
||||
|
||||
function doClick() {
|
||||
count1.value += 1;
|
||||
}
|
||||
|
||||
function doSelect(option) {
|
||||
if ($empty(option)) return;
|
||||
emit("option", option);
|
||||
emit("modalevent", { name: "option", data: option });
|
||||
selected.value = option;
|
||||
value.value = selected.value[props.field];
|
||||
}
|
||||
|
||||
function clearValue() {
|
||||
value.value = undefined;
|
||||
selected.value = undefined;
|
||||
emit("option", null);
|
||||
emit("modalevent", { name: "option", data: null });
|
||||
}
|
||||
|
||||
function findObject(val) {
|
||||
const rows = $copy(orgdata.value);
|
||||
if ($empty(val)) data.value = rows;
|
||||
else {
|
||||
let text = this.$nonAccent(val);
|
||||
this.data = rows.filter((v) => v.search.toLowerCase().indexOf(text.toLowerCase()) >= 0);
|
||||
const text = $nonAccent(val);
|
||||
data.value = rows.filter((v) => v.search.toLowerCase().indexOf(text.toLowerCase()) >= 0);
|
||||
}
|
||||
},
|
||||
async getData() {
|
||||
this.isLoading = false;
|
||||
this.params.filter = this.filter;
|
||||
let data = await this.$getdata(this.api, undefined, this.params);
|
||||
this.isLoading = true;
|
||||
}
|
||||
|
||||
async function getData() {
|
||||
isLoading.value = false;
|
||||
params.value.filter = props.filter;
|
||||
const data = await $getdata(props.api, undefined, params.value);
|
||||
isLoading.value = true;
|
||||
return data;
|
||||
},
|
||||
async getApi(val) {
|
||||
if (this.vdata) return this.findObject(val);
|
||||
let text = val ? val.toLowerCase() : "";
|
||||
let f = {};
|
||||
}
|
||||
|
||||
async function getApi(val) {
|
||||
if (props.vdata) return findObject(val);
|
||||
const text = val ? val.toLowerCase() : "";
|
||||
const f = {};
|
||||
|
||||
// Sử dụng searchfield nếu có, nếu không thì dùng column
|
||||
const fieldsToSearch = this.searchfield || this.column;
|
||||
const fieldsToSearch = props.searchfield || props.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);
|
||||
},
|
||||
beginSearch(e) {
|
||||
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);
|
||||
},
|
||||
dataevent(v) {
|
||||
params.value.filter_or = f;
|
||||
if (props.filter) params.value.filter = $copy(props.filter);
|
||||
data.value = await $getdata(props.api, undefined, params.value);
|
||||
}
|
||||
|
||||
function beginSearch(e) {
|
||||
const val = e.target.value;
|
||||
search.value = val;
|
||||
clearTimeout(timer.value);
|
||||
timer.value = setTimeout(() => getApi(val), 150);
|
||||
}
|
||||
|
||||
function addNew() {
|
||||
showmodal.value = props.addon;
|
||||
}
|
||||
|
||||
function dataevent(v) {
|
||||
console.log("SearchBox received dataevent:", v); // Debug log
|
||||
|
||||
if (!v || !v.id) {
|
||||
@@ -321,70 +327,70 @@ export default {
|
||||
}
|
||||
|
||||
// Tìm và cập nhật trong danh sách
|
||||
let idx = this.$findIndex(this.data, { id: v.id });
|
||||
const idx = $findIndex(data.value, { id: v.id });
|
||||
if (idx < 0) {
|
||||
// Nếu chưa có trong danh sách, thêm vào đầu
|
||||
this.data.unshift(v);
|
||||
data.value.unshift(v);
|
||||
console.log("Added new item to data:", v);
|
||||
} else {
|
||||
// Nếu đã có, cập nhật
|
||||
this.data[idx] = v;
|
||||
data.value[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 });
|
||||
if (orgdata.value) {
|
||||
let orgIdx = $findIndex(orgdata.value, { id: v.id });
|
||||
if (orgIdx < 0) {
|
||||
this.orgdata.unshift(v);
|
||||
orgdata.value.unshift(v);
|
||||
// Thêm search field cho orgdata
|
||||
if (this.field && v[this.field]) {
|
||||
v.search = this.$nonAccent(v[this.field]);
|
||||
if (props.field && v[props.field]) {
|
||||
v.search = $nonAccent(v[props.field]);
|
||||
}
|
||||
} else {
|
||||
this.orgdata[orgIdx] = v;
|
||||
if (this.field && v[this.field]) {
|
||||
this.orgdata[orgIdx].search = this.$nonAccent(v[this.field]);
|
||||
orgdata.value[orgIdx] = v;
|
||||
if (props.field && v[props.field]) {
|
||||
orgdata.value[orgIdx].search = $nonAccent(v[props.field]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **Tự động select item vừa tạo/cập nhật**
|
||||
this.doSelect(v);
|
||||
doSelect(v);
|
||||
|
||||
// Đóng modal
|
||||
this.showmodal = undefined;
|
||||
showmodal.value = undefined;
|
||||
console.log("SearchBox data after update:", data.value);
|
||||
}
|
||||
|
||||
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",
|
||||
function viewInfo() {
|
||||
if (!selected.value)
|
||||
return $dialog(
|
||||
$store.lang === "vi" ? "Vui lòng lựa chọn trước khi xem thông tin." : "Please select before viewing",
|
||||
$store.lang === "vi" ? "Thông báo" : "Notice",
|
||||
);
|
||||
let copy = this.$copy(this.viewaddon);
|
||||
copy.vbind = { row: this.selected };
|
||||
this.showmodal = copy;
|
||||
},
|
||||
getPos() {
|
||||
switch (this.position) {
|
||||
showmodal.value = {
|
||||
...props.viewaddon,
|
||||
vbind: { row: selected.value },
|
||||
};
|
||||
}
|
||||
|
||||
function getPos() {
|
||||
switch (props.position) {
|
||||
case "is-top-left":
|
||||
this.pos = "is-up is-left";
|
||||
pos.value = "is-up is-left";
|
||||
break;
|
||||
case "is-top-right":
|
||||
this.pos = "is-up is-right";
|
||||
pos.value = "is-up is-right";
|
||||
break;
|
||||
case "is-bottom-left":
|
||||
this.pos = "is-right";
|
||||
pos.value = "is-right";
|
||||
break;
|
||||
case "is-bottom-right":
|
||||
this.pos = "is-right";
|
||||
pos.value = "is-right";
|
||||
break;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.field:not(:last-child) {
|
||||
|
||||
Reference in New Issue
Block a user