feat: ค้นหาตรงตัว

This commit is contained in:
puri-ph4tt 2023-12-15 09:02:39 +07:00
parent 65b05737fb
commit 2e54da99e1
2 changed files with 152 additions and 115 deletions

View file

@ -1,4 +1,3 @@
divdivdivdivdivdiv
<script setup lang="ts"> <script setup lang="ts">
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
@ -22,10 +21,12 @@ const props = defineProps<{
AND: { AND: {
field: string field: string
value: string value: string
exact: boolean
}[] }[]
OR: { OR: {
field: string field: string
value: string value: string
exact: boolean
}[] }[]
} }
}>() }>()
@ -35,6 +36,7 @@ function addAdvSearchData() {
op: 'AND', op: 'AND',
field: 'title', field: 'title',
value: '', value: '',
exact: false,
}) })
} }
function delAdvSearchData(index: number) { function delAdvSearchData(index: number) {
@ -47,6 +49,7 @@ function clearAdvSearchData() {
op: 'AND', op: 'AND',
field: 'title', field: 'title',
value: '', value: '',
exact: false,
}, },
] ]
advSearchDataField.value = { advSearchDataField.value = {
@ -71,7 +74,7 @@ function clearAdvSearchData() {
</div> </div>
<div v-if="isAdvSearchCall === true"> <div v-if="isAdvSearchCall === true">
<div class="column bg-white q-pa-sm"> <div class="col bg-white q-pa-sm">
<div class="row items-center justify-between q-pb-md"> <div class="row items-center justify-between q-pb-md">
<span class="text-primary text-weight-medium q-pl-md q-pt-xs" <span class="text-primary text-weight-medium q-pl-md q-pt-xs"
><q-icon name="mdi-tools" class="q-pr-sm" size="sm" /> ><q-icon name="mdi-tools" class="q-pr-sm" size="sm" />
@ -87,112 +90,123 @@ function clearAdvSearchData() {
/> />
</div> </div>
<div class="column q-px-lg"> <div
class="row q-px-lg items-center justify-start q-pb-md q-col-gutter-md"
v-for="(item, index) in advSearchDataRow"
:key="index"
>
<div <div
class="row items-center q-pb-xs q-col-gutter-md" class="col-md-1 col-1 row content-center"
v-for="(item, index) in advSearchDataRow" style="width: 45px; height: 45px"
:key="index"
> >
<div class="row content-center" style="width: 45px; height: 45px"> <q-btn
<q-btn dense
dense color="teal-5"
color="teal-5" icon="mdi-plus"
icon="mdi-plus" v-if="index === advSearchDataRow.length - 1"
v-if="index === advSearchDataRow.length - 1" @click="addAdvSearchData"
@click="addAdvSearchData" id="addAdvSearchData"
id="addAdvSearchData" />
/>
</div>
<div class="col-4 col-md-2">
<q-select
id="advSearchOp"
dense
outlined
emit-value
map-options
v-model="item.op"
:options="optionsOp"
/>
</div>
<div class="col-grow col-md-3">
<q-select
id="advSearchField"
dense
outlined
emit-value
map-options
v-model="item.field"
:options="optionsField"
/>
</div>
<div class="col-grow">
<q-input
id="advSearchValue"
dense
outlined
v-model="item.value"
placeholder="เอกสาร"
@keydown.enter.prevent="submitSearch()"
><template v-slot:append>
<q-icon
v-if="item.value"
name="close"
@click="() => (item.value = '')"
class="cursor-pointer"
/>
</template>
</q-input>
</div>
<div class="row content-center" style="width: 45px; height: 45px">
<q-btn
dense
flat
icon="mdi-trash-can-outline"
v-if="advSearchDataRow.length > 1"
color="red"
@click="() => delAdvSearchData(index)"
id="delAdvSearchData"
/>
</div>
</div> </div>
<div class="col-4 col-md-2">
<q-select
id="advSearchOp"
dense
outlined
emit-value
map-options
v-model="item.op"
:options="optionsOp"
/>
</div>
<div class="col-grow col-md-3">
<q-select
id="advSearchField"
dense
outlined
emit-value
map-options
v-model="item.field"
:options="optionsField"
/>
</div>
<div class="col-md-grow col-grow">
<q-input
id="advSearchValue"
dense
outlined
v-model="item.value"
placeholder="เอกสาร"
@keydown.enter.prevent="submitSearch()"
><template v-slot:append>
<q-icon
v-if="item.value"
name="close"
@click="() => (item.value = '')"
class="cursor-pointer"
/>
</template>
</q-input>
</div>
<div class="col-md-1 q-mr-xl">
<q-checkbox
id="specificBox"
style="width: 200%"
v-model="item.exact"
label="ค้นหาตรงตัว"
color="grey"
keep-color
/>
</div>
<div class="row content-center">
<q-btn
dense
flat
icon="mdi-trash-can-outline"
v-if="advSearchDataRow.length > 1"
color="red"
@click="() => delAdvSearchData(index)"
id="delAdvSearchData"
/>
</div>
</div>
<q-separator class="q-mb-md q-mt-sm" /> <q-separator class="q-mb-md q-mt-sm" />
<div class="row q-col-gutter-md q-pb-md"> <div class="row q-col-gutter-md q-pb-md q-pt-sm">
<div class="col-12 col-md-5"> <div class="col-12 col-md-5">
<q-select <q-select
outlined outlined
dense dense
v-model="advSearchDataField.keyword" v-model="advSearchDataField.keyword"
use-input use-input
use-chips use-chips
multiple multiple
hide-dropdown-icon hide-dropdown-icon
input-debounce="0" input-debounce="0"
new-value-mode="add-unique" new-value-mode="add-unique"
><template v-slot:prepend ><template v-slot:prepend
><span class="text-subtitle2">คำสำค:</span></template ><span class="text-subtitle2">คำสำค:</span></template
></q-select ></q-select
> >
</div> </div>
<div class="col-12 col-md-grow"> <div class="col-12 col-md-grow">
<q-input <q-input
id="advSearchDes" id="advSearchDes"
dense dense
outlined outlined
@keydown.enter.prevent="submitSearch()" @keydown.enter.prevent="submitSearch()"
v-model="advSearchDataField.description" v-model="advSearchDataField.description"
><template v-slot:prepend ><template v-slot:prepend
><span class="text-subtitle2">รายละเอยด:</span></template ><span class="text-subtitle2">รายละเอยด:</span></template
><template v-slot:append> ><template v-slot:append>
<q-icon <q-icon
v-if="advSearchDataField.description" v-if="advSearchDataField.description"
name="close" name="close"
@click="() => (advSearchDataField.description = '')" @click="() => (advSearchDataField.description = '')"
class="cursor-pointer" class="cursor-pointer"
/> </template /> </template
></q-input> ></q-input>
</div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -16,6 +16,7 @@ const loaderStore = useLoader()
const { isFilePreview } = storeToRefs(useFileInfoStore()) const { isFilePreview } = storeToRefs(useFileInfoStore())
const { const {
foundFile, foundFile,
isExact,
isSearch, isSearch,
isAdvSearchCall, isAdvSearchCall,
isActFoundFile, isActFoundFile,
@ -31,8 +32,8 @@ const optionsField = [
{ label: 'เนื้อหาในไฟล์ (content)', value: 'attachment.content' }, { label: 'เนื้อหาในไฟล์ (content)', value: 'attachment.content' },
] ]
const submitSearchData = ref<{ const submitSearchData = ref<{
AND: { field: string; value: string }[] AND: { field: string; value: string; exact: boolean }[]
OR: { field: string; value: string }[] OR: { field: string; value: string; exact: boolean }[]
}>({ }>({
AND: [], AND: [],
OR: [], OR: [],
@ -40,7 +41,6 @@ const submitSearchData = ref<{
const props = defineProps<{ const props = defineProps<{
mode: 'admin' | 'user' mode: 'admin' | 'user'
}>() }>()
const socket = io(import.meta.env.VITE_API_HOST) const socket = io(import.meta.env.VITE_API_HOST)
socket.on('FileUpdate', (data: StorageFile) => socket.on('FileUpdate', (data: StorageFile) =>
@ -68,36 +68,47 @@ async function submitSearch() {
submitSearchData.value.OR.push({ submitSearchData.value.OR.push({
field: option.value, field: option.value,
value: searchData.value.value, value: searchData.value.value,
exact: true,
}) })
}) })
submitSearchData.value.OR.push({ submitSearchData.value.OR.push({
field: 'fileName', field: 'fileName',
value: searchData.value.value, value: searchData.value.value,
exact: true,
}) })
submitSearchData.value.OR.push({ submitSearchData.value.OR.push({
field: 'fileType', field: 'fileType',
value: mime.getType(searchData.value.value) || '', value: mime.getType(searchData.value.value) || '',
exact: true,
}) })
} else { } else {
submitSearchData.value.OR.push({ submitSearchData.value.OR.push({
field: searchData.value.field, field: searchData.value.field,
value: searchData.value.value, value: searchData.value.value,
exact: isExact.value,
}) })
if (isAdvSearchCall.value) { if (isAdvSearchCall.value) {
let advField = advSearchDataField.value let advField = advSearchDataField.value
let advRow = advSearchDataRow.value let advRow = advSearchDataRow.value
advRow.forEach((d: { field: string; value: string; op: string }) => { advRow.forEach(
if (d.field && d.value.trim() !== '') { (d: { field: string; value: string; op: string; exact: boolean }) => {
const op = d.op === 'AND' ? 'AND' : 'OR' if (d.field && d.value.trim() !== '') {
submitSearchData.value[op].push({ field: d.field, value: d.value }) const op = d.op === 'AND' ? 'AND' : 'OR'
} submitSearchData.value[op].push({
}) field: d.field,
value: d.value,
exact: d.exact,
})
}
},
)
if (advField.keyword.length > 0) { if (advField.keyword.length > 0) {
for (let i = 0; i < advField.keyword.length; i++) { for (let i = 0; i < advField.keyword.length; i++) {
submitSearchData.value.AND.push({ submitSearchData.value.AND.push({
field: 'keyword', field: 'keyword',
value: advField.keyword[i], value: advField.keyword[i],
exact: true,
}) })
} }
} }
@ -105,6 +116,7 @@ async function submitSearch() {
submitSearchData.value.AND.push({ submitSearchData.value.AND.push({
field: 'description', field: 'description',
value: advField.description, value: advField.description,
exact: true,
}) })
} }
} }
@ -116,6 +128,7 @@ async function submitSearch() {
`${import.meta.env.VITE_API_ENDPOINT}/search`, `${import.meta.env.VITE_API_ENDPOINT}/search`,
submitSearchData.value, submitSearchData.value,
) )
getFoundFile(res.data) getFoundFile(res.data)
isSearch.value = true isSearch.value = true
} catch (error) { } catch (error) {
@ -133,7 +146,7 @@ watch(
submitSearch() submitSearch()
setTimeout(() => { setTimeout(() => {
isActFoundFile.value = false isActFoundFile.value = false
}, 300) }, 1000)
} }
}, },
) )
@ -206,11 +219,20 @@ watch(
</template> </template>
</q-input> </q-input>
</div> </div>
<div>
<q-checkbox
id="specificBox"
v-model="isExact"
label="ค้นหาตรงตัว"
color="grey"
keep-color
/>
</div>
</div> </div>
<div class="column"> <div class="col">
<div class="row items-center justify-between q-gutter-y-md q-pt-sm"> <div class="row items-center justify-between q-gutter-y-md q-pt-sm">
<div class="column col-grow"> <div class="col-grow">
<advanced-search <advanced-search
:submitSearch="submitSearch" :submitSearch="submitSearch"
:submit-search-data="submitSearchData" :submit-search-data="submitSearchData"
@ -221,6 +243,7 @@ watch(
style="width: 150px" style="width: 150px"
color="primary" color="primary"
label="ค้นหา" label="ค้นหา"
class="q-mt-sm"
icon="mdi-magnify" icon="mdi-magnify"
@click="submitSearch" @click="submitSearch"
id="submitSearch" id="submitSearch"