client initial commit
This commit is contained in:
parent
b5f98baa2b
commit
dd1547d7c2
70 changed files with 18446 additions and 0 deletions
|
|
@ -0,0 +1,220 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
const isAdvncSearchClick = ref<boolean>(false)
|
||||
const optionsField = [
|
||||
{ label: 'ชื่อเรื่อง (title)', value: 'title' },
|
||||
{ label: 'คำสำคัญ (keyword)', value: 'keyword' },
|
||||
]
|
||||
const optionsOp = [
|
||||
{ label: 'และ', value: 'AND' },
|
||||
{ label: 'หรือ', value: 'OR' },
|
||||
]
|
||||
const advSearchData = ref<
|
||||
{
|
||||
op: 'AND' | 'OR'
|
||||
field: 'title' | 'keyword'
|
||||
value: string
|
||||
}[]
|
||||
>([])
|
||||
const props = defineProps<{
|
||||
field: string
|
||||
value: string
|
||||
keyword?: string
|
||||
description?: string
|
||||
searchSubmit: Function
|
||||
submitSearchData: {
|
||||
AND: {
|
||||
field?: string
|
||||
value?: string
|
||||
}[]
|
||||
OR: {
|
||||
field: string
|
||||
value: string
|
||||
}[]
|
||||
}
|
||||
}>()
|
||||
|
||||
defineExpose({
|
||||
clearAdvData,
|
||||
advSearchData,
|
||||
})
|
||||
|
||||
defineEmits([
|
||||
'update:field',
|
||||
'update:value',
|
||||
'update:keyword',
|
||||
'update:description',
|
||||
])
|
||||
|
||||
function addSearchData() {
|
||||
advSearchData.value.push({
|
||||
op: 'AND',
|
||||
field: 'title',
|
||||
value: '',
|
||||
})
|
||||
}
|
||||
|
||||
function clearAdvData() {
|
||||
advSearchData.value = []
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<q-btn
|
||||
outline
|
||||
color="primary"
|
||||
icon="mdi-tools"
|
||||
label="ค้นหาขั้นสูง"
|
||||
@click="() => (isAdvncSearchClick = true)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<q-dialog v-model="isAdvncSearchClick">
|
||||
<q-card style="width: 1000px; max-width: 80vw">
|
||||
<q-toolbar class="bg-grey-1 q-py-sm q-px-lg">
|
||||
<q-toolbar-title>
|
||||
<span class="text-weight-bold">ค้นหาขั้นสูง</span>
|
||||
</q-toolbar-title>
|
||||
<q-btn flat round dense icon="close" v-close-popup color="red" />
|
||||
</q-toolbar>
|
||||
<q-separator />
|
||||
|
||||
<div class="col">
|
||||
<q-card-section class="row q-mt-sm">
|
||||
<div class="col">
|
||||
<div class="row q-col-gutter-md q-mb-md items-center">
|
||||
<div class="col-12 col-md-3">
|
||||
<q-select
|
||||
dense
|
||||
outlined
|
||||
emit-value
|
||||
map-options
|
||||
:options="optionsField"
|
||||
:model-value="props.field"
|
||||
@update:model-value="(value) => $emit('update:field', value)"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 col-md-8">
|
||||
<q-input
|
||||
dense
|
||||
outlined
|
||||
placeholder="เอกสาร"
|
||||
:model-value="props.value"
|
||||
@update:model-value="(value) => $emit('update:value', value)"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<q-btn
|
||||
dense
|
||||
color="teal"
|
||||
icon="mdi-plus"
|
||||
v-if="advSearchData.length === 0"
|
||||
@click="addSearchData"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="row q-col-gutter-md q-mb-md items-center"
|
||||
v-for="(_, index) in advSearchData"
|
||||
>
|
||||
<div class="col-4 col-md-2">
|
||||
<q-select
|
||||
dense
|
||||
outlined
|
||||
emit-value
|
||||
map-options
|
||||
v-model="advSearchData[index].op"
|
||||
:options="optionsOp"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-8 col-md-3">
|
||||
<q-select
|
||||
dense
|
||||
outlined
|
||||
emit-value
|
||||
map-options
|
||||
v-model="advSearchData[index].field"
|
||||
:options="optionsField"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<q-input
|
||||
dense
|
||||
outlined
|
||||
v-model="advSearchData[index].value"
|
||||
placeholder="เอกสาร"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<q-btn
|
||||
dense
|
||||
color="teal"
|
||||
icon="mdi-plus"
|
||||
v-if="index === advSearchData.length - 1"
|
||||
@click="addSearchData"
|
||||
/>
|
||||
<q-btn
|
||||
dense
|
||||
flat
|
||||
icon="mdi-minus"
|
||||
color="red"
|
||||
v-if="index === advSearchData.length - 1"
|
||||
@click="() => advSearchData.pop()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="row q-mb-md">
|
||||
<div class="col">
|
||||
<span>อื่น ๆ</span>
|
||||
<q-separator class="q-mb-lg" />
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-3 q-gutter-y-sm">
|
||||
<span class="text-weight-bold">คำสำคัญ</span>
|
||||
<q-input
|
||||
dense
|
||||
outlined
|
||||
placeholder="กรอกคำสำคัญ"
|
||||
:model-value="props.keyword"
|
||||
@update:model-value="
|
||||
(value) => $emit('update:keyword', value)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 col-md-4 q-gutter-y-sm">
|
||||
<span class="text-weight-bold">รายละเอียดของเอกสาร</span>
|
||||
<q-input
|
||||
dense
|
||||
outlined
|
||||
placeholder="กรอกรายละเอียด"
|
||||
:model-value="props.description"
|
||||
@update:model-value="
|
||||
(value) => $emit('update:description', value)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-separator />
|
||||
|
||||
<q-toolbar class="row justify-end">
|
||||
<div class="q-py-md">
|
||||
<q-btn
|
||||
color="primary"
|
||||
label="ค้นหา"
|
||||
icon="mdi-magnify"
|
||||
v-close-popup
|
||||
@click="() => props.searchSubmit()"
|
||||
/>
|
||||
</div>
|
||||
</q-toolbar>
|
||||
</div>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</template>
|
||||
188
Services/client/src/modules/01_user/components/SearchBar.vue
Normal file
188
Services/client/src/modules/01_user/components/SearchBar.vue
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
<script setup lang="ts">
|
||||
import axios from 'axios'
|
||||
import { ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
import type { EhrFile } from '@/stores/tree-data'
|
||||
|
||||
import AdvancedSearch from '@/modules/01_user/components/AdvancedSearch.vue'
|
||||
import { useSearchDataStore } from '@/stores/searched-data'
|
||||
import { useLoader } from '@/stores/loader'
|
||||
|
||||
const loaderStore = useLoader()
|
||||
const { isSearch } = storeToRefs(useSearchDataStore())
|
||||
const { getFoundFile } = useSearchDataStore()
|
||||
const advSearchComp = ref<InstanceType<typeof AdvancedSearch>>()
|
||||
const isAdvSearchCall = ref<boolean>(false)
|
||||
const optionsField = [
|
||||
{ label: 'ชื่อเรื่อง (title)', value: 'title' },
|
||||
{ label: 'คำสำคัญ (keyword)', value: 'keyword' },
|
||||
]
|
||||
const searchData = ref<{
|
||||
field: string
|
||||
value: string
|
||||
keyword?: string
|
||||
description?: string
|
||||
}>({
|
||||
field: 'title',
|
||||
value: '',
|
||||
keyword: '',
|
||||
description: '',
|
||||
})
|
||||
const submitSearchData = ref<{
|
||||
AND: {
|
||||
field?: string
|
||||
value?: string
|
||||
}[]
|
||||
OR: { field: string; value: string }[]
|
||||
}>({
|
||||
AND: [],
|
||||
OR: [],
|
||||
})
|
||||
|
||||
function clearSearchData() {
|
||||
searchData.value = {
|
||||
field: 'title',
|
||||
value: '',
|
||||
keyword: '',
|
||||
description: '',
|
||||
}
|
||||
submitSearchData.value = {
|
||||
AND: [],
|
||||
OR: [],
|
||||
}
|
||||
advSearchComp.value?.clearAdvData()
|
||||
isAdvSearchCall.value = false
|
||||
isSearch.value = false
|
||||
}
|
||||
|
||||
async function searchSubmit() {
|
||||
submitSearchData.value = {
|
||||
AND: [],
|
||||
OR: [],
|
||||
}
|
||||
if (searchData.value.field && searchData.value) {
|
||||
submitSearchData.value?.AND.push({
|
||||
field: searchData.value.field,
|
||||
value: searchData.value.value,
|
||||
})
|
||||
if (searchData.value.keyword) {
|
||||
submitSearchData.value?.AND.push({
|
||||
field: 'keyword',
|
||||
value: searchData.value.keyword,
|
||||
})
|
||||
}
|
||||
if (searchData.value.description) {
|
||||
submitSearchData.value?.AND.push({
|
||||
field: 'description',
|
||||
value: searchData.value.description,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (isAdvSearchCall.value) {
|
||||
if (
|
||||
advSearchComp.value?.advSearchData &&
|
||||
advSearchComp.value.advSearchData.length > 0
|
||||
) {
|
||||
advSearchComp.value?.advSearchData.forEach(
|
||||
(d: { field: string; value: string; op: string }) => {
|
||||
if (d.field && d.value) {
|
||||
if (d.op === 'AND') {
|
||||
submitSearchData.value.AND.push({
|
||||
field: d.field,
|
||||
value: d.value,
|
||||
})
|
||||
} else if (d.op === 'OR') {
|
||||
submitSearchData.value.OR.push({ field: d.field, value: d.value })
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
try {
|
||||
loaderStore.show()
|
||||
isAdvSearchCall.value = true
|
||||
const res = await axios.post<EhrFile[]>(
|
||||
`${import.meta.env.VITE_API_ENDPOINT}/search`,
|
||||
submitSearchData.value
|
||||
)
|
||||
getFoundFile(res.data)
|
||||
isSearch.value = true
|
||||
} catch (error) {
|
||||
console.error('Error during the request', error)
|
||||
} finally {
|
||||
loaderStore.hide()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="q-py-lg q-px-md bg-grey-1">
|
||||
<div class="row items-center q-gutter-md">
|
||||
<div class="col-12 col-md-3">
|
||||
<q-select
|
||||
dense
|
||||
outlined
|
||||
emit-value
|
||||
map-options
|
||||
class="bg-white"
|
||||
v-model="searchData.field"
|
||||
:options="optionsField"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 col-md-grow">
|
||||
<q-input
|
||||
class="bg-white"
|
||||
dense
|
||||
outlined
|
||||
v-model="searchData.value"
|
||||
placeholder="เอกสาร"
|
||||
@keydown.enter.prevent="searchSubmit"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="isAdvSearchCall === false">
|
||||
<q-btn
|
||||
class="col-12 col-md-2"
|
||||
color="primary"
|
||||
label="ค้นหา"
|
||||
icon="mdi-magnify"
|
||||
@click="() => searchSubmit()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="isAdvSearchCall"
|
||||
class="row items-center justify-between q-gutter-y-md q-mt-xs"
|
||||
>
|
||||
<div>
|
||||
<advanced-search
|
||||
ref="advSearchComp"
|
||||
:searchSubmit="searchSubmit"
|
||||
:submit-search-data="submitSearchData"
|
||||
v-model:field="searchData.field"
|
||||
v-model:value="searchData.value"
|
||||
v-model:keyword="searchData.keyword"
|
||||
v-model:description="searchData.description"
|
||||
/>
|
||||
</div>
|
||||
<div class="q-gutter-x-md">
|
||||
<q-btn
|
||||
color="primary"
|
||||
label="ค้นหา"
|
||||
icon="mdi-magnify"
|
||||
@click="searchSubmit"
|
||||
/>
|
||||
<q-btn
|
||||
color="orange-12"
|
||||
label="ล้างข้อมูล"
|
||||
icon="close"
|
||||
@click="clearSearchData"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<q-separator />
|
||||
</template>
|
||||
9
Services/client/src/modules/01_user/router.ts
Normal file
9
Services/client/src/modules/01_user/router.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// const adminHomePage = () => import('@/modules/02_transfer/views/Main.vue')
|
||||
|
||||
export default [
|
||||
{
|
||||
path: '/',
|
||||
name: 'UserHomePage',
|
||||
component: () => import('@/modules/01_user/views/homePage.vue')
|
||||
}
|
||||
]
|
||||
8
Services/client/src/modules/01_user/views/homePage.vue
Normal file
8
Services/client/src/modules/01_user/views/homePage.vue
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import PageLayout from '@/components/PageLayout.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<page-layout mode="user" />
|
||||
</template>
|
||||
<style scoped></style>
|
||||
9
Services/client/src/modules/02_admin/router.ts
Normal file
9
Services/client/src/modules/02_admin/router.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// const adminHomePage = () => import('@/modules/02_transfer/views/Main.vue')
|
||||
|
||||
export default [
|
||||
{
|
||||
path: '/admin',
|
||||
name: 'AdminHomePage',
|
||||
component: () => import('@/modules/02_admin/views/homePage.vue')
|
||||
}
|
||||
]
|
||||
18
Services/client/src/modules/02_admin/views/homePage.vue
Normal file
18
Services/client/src/modules/02_admin/views/homePage.vue
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<script setup lang="ts">
|
||||
import PageLayout from '@/components/PageLayout.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<page-layout mode="admin" />
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
#container > [class^='col'] > * {
|
||||
border: 1px solid $separator-color;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#container-header {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue