changes
This commit is contained in:
202
components/SearchBox.vue
Normal file
202
components/SearchBox.vue
Normal file
@@ -0,0 +1,202 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="field has-addons">
|
||||
<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" v-model="value" />
|
||||
</div>
|
||||
<div class="dropdown-menu" role="menu">
|
||||
<div class="dropdown-content px-3" style="min-width: 250px;">
|
||||
<p class="has-text-findata" v-if="data.length===0">Không có giá trị thỏa mãn</p>
|
||||
<ScrollBox v-bind="{data: data, name: field, fontsize: 14, maxheight: '200px'}" @selected="choose" v-else></ScrollBox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="icon is-left">
|
||||
<SvgIcon v-bind="{name: 'magnify.svg', type: 'gray', size: 22}"></SvgIcon>
|
||||
</span>
|
||||
</div>
|
||||
<div class="control" v-if="viewaddon">
|
||||
<button class="button is-dark px-2" @click="viewInfo()">
|
||||
<SvgIcon v-bind="{name: 'view.svg', type: 'white', size: 22}"></SvgIcon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="control" v-if="addon">
|
||||
<button class="button is-primary px-2" @click="addNew()">
|
||||
<SvgIcon v-bind="{name: 'add1.png', type: 'white', size: 22}"></SvgIcon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<Modal @dataevent="dataevent" @close="showmodal=undefined" v-bind="showmodal" v-if="showmodal"></Modal>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
const emit = defineEmits(['option', 'modalevent'])
|
||||
import ScrollBox from '~/components/datatable/ScrollBox'
|
||||
const { $nonAccent, $find, $getdata, $copy, $empty, $findapi, $findIndex} = useNuxtApp()
|
||||
var props = defineProps({
|
||||
api: String,
|
||||
field: String,
|
||||
column: Array,
|
||||
first: Boolean,
|
||||
optionid: Number,
|
||||
filter: Object,
|
||||
addon: Object,
|
||||
viewaddon: Object,
|
||||
position: String,
|
||||
disabled: Boolean,
|
||||
vdata: Object
|
||||
})
|
||||
var search = undefined
|
||||
var data = ref([])
|
||||
var timer = undefined
|
||||
var value = ref()
|
||||
var selected = undefined
|
||||
var showmodal = ref()
|
||||
var params = props.api? $findapi(props.api)['params'] : {}
|
||||
var orgdata = undefined
|
||||
var error = false
|
||||
var focused = ref(false)
|
||||
var count1 = 0
|
||||
var count2 = 0
|
||||
var pos = undefined
|
||||
async function initData() {
|
||||
getPos()
|
||||
if(props.vdata) {
|
||||
orgdata = $copy(props.vdata)
|
||||
orgdata.map(v=>v.search = $nonAccent(v[props.field]))
|
||||
}
|
||||
if(props.first) {
|
||||
data.value = orgdata? $copy(orgdata) : await getData()
|
||||
if(props.optionid) {
|
||||
let f = {}
|
||||
f[props.field] = props.optionid
|
||||
if(props.optionid>0) f = {id: props.optionid}
|
||||
selected = $find(data.value, f)
|
||||
if(selected && props.vdata) {
|
||||
return value.value = selected[props.field]
|
||||
}
|
||||
}
|
||||
} else if(props.optionid) {
|
||||
selected = await $getdata(props.api, {id: props.optionid}, undefined, true)
|
||||
}
|
||||
if(selected) doSelect(selected)
|
||||
}
|
||||
/*watch(()=> {
|
||||
optionid: function(newVal) {
|
||||
if(optionid) selected = $find(data, {id: optionid})
|
||||
if(selected) doSelect(selected)
|
||||
else value = undefined
|
||||
}
|
||||
filter: async function(newVal) {
|
||||
data = await getData()
|
||||
},
|
||||
vdata: function(newval) {
|
||||
if(newval) {
|
||||
orgdata = $copy(props.vdata)
|
||||
orgdata.map(v=>v.search = $nonAccent(v[field]))
|
||||
data = $copy(orgdata)
|
||||
selected = undefined
|
||||
value = undefined
|
||||
if(optionid) selected = $find(data, {id: optionid})
|
||||
if(selected) doSelect(selected)
|
||||
}
|
||||
}
|
||||
}}*/
|
||||
function choose(v) {
|
||||
focused.value = false
|
||||
count1 = 0
|
||||
count2 = 0
|
||||
doSelect(v)
|
||||
}
|
||||
function setFocus() {
|
||||
focused.value = true
|
||||
count1 = 0
|
||||
count2 = 0
|
||||
}
|
||||
function lostFocus() {
|
||||
setTimeout(()=>{
|
||||
focused.value = false
|
||||
if($empty(value.value)) emit('option', null)
|
||||
}, 200)
|
||||
}
|
||||
function pressEnter() {
|
||||
if(data.length===0) return
|
||||
choose(data[0])
|
||||
}
|
||||
function doClick() {
|
||||
count1 += 1
|
||||
}
|
||||
function doSelect(option) {
|
||||
if($empty(option)) return
|
||||
selected = option
|
||||
value.value = selected[props.field]
|
||||
emit('option', option)
|
||||
emit('modalevent', {name: 'option', data: option})
|
||||
}
|
||||
function findObject(val) {
|
||||
let rows = $copy(orgdata)
|
||||
if($empty(val)) data.value = rows
|
||||
else {
|
||||
let text = $nonAccent(val)
|
||||
data.value = rows.filter(v=>v.search.toLowerCase().indexOf(text.toLowerCase())>=0)
|
||||
}
|
||||
}
|
||||
async function getData() {
|
||||
params.filter = props.filter
|
||||
params.sort = '-id'
|
||||
let data = await $getdata(props.api, undefined, params)
|
||||
return data
|
||||
}
|
||||
async function getApi(val) {
|
||||
if(props.vdata) return findObject(val)
|
||||
let text = val? val.toLowerCase() : ''
|
||||
let f = {}
|
||||
props.column.map(v=>{
|
||||
f[`${v}__icontains`] = text
|
||||
})
|
||||
params.filter_or = f
|
||||
if(props.filter) params.filter = $copy(props.filter)
|
||||
data.value = await $getdata(props.api, undefined, params)
|
||||
}
|
||||
function beginSearch(e) {
|
||||
let val = e.target.value
|
||||
search = val
|
||||
if (timer) clearTimeout(timer)
|
||||
timer = setTimeout(() => getApi(val), 150)
|
||||
if($empty(val)) emit('option', null)
|
||||
}
|
||||
function addNew() {
|
||||
showmodal.value = $copy(props.addon)
|
||||
}
|
||||
function dataevent(v) {
|
||||
let idx = $findIndex(data.value, {id: v.id})
|
||||
idx<0? data.value.push(v) : data.value[idx] = v
|
||||
doSelect(v)
|
||||
}
|
||||
function viewInfo() {
|
||||
if(!selected) return $dialog('Vui lòng lựa chọn trước khi xem thông tin.', 'Thông báo')
|
||||
let copy = $copy(props.viewaddon)
|
||||
copy.vbind = {row: selected}
|
||||
showmodal.value = copy
|
||||
}
|
||||
function getPos() {
|
||||
switch(props.position) {
|
||||
case 'is-top-left':
|
||||
pos = 'is-up is-left'
|
||||
break;
|
||||
case 'is-top-right':
|
||||
pos = 'is-up is-right'
|
||||
break;
|
||||
case 'is-bottom-left':
|
||||
pos = 'is-right'
|
||||
break;
|
||||
case 'is-bottom-right':
|
||||
pos = 'is-right'
|
||||
break;
|
||||
}
|
||||
}
|
||||
initData()
|
||||
</script>
|
||||
Reference in New Issue
Block a user