Merge branch 'phatt' into development
This commit is contained in:
commit
f2303bee8b
6 changed files with 283 additions and 69 deletions
|
|
@ -190,6 +190,7 @@ const file = ref<File | undefined>()
|
|||
<div class="q-mt-md">
|
||||
<q-select
|
||||
outlined
|
||||
dense
|
||||
:model-value="category"
|
||||
label="กดปุ่มEnterเพื่อเพิ่ม"
|
||||
use-input
|
||||
|
|
@ -217,6 +218,7 @@ const file = ref<File | undefined>()
|
|||
<div class="q-mt-md">
|
||||
<q-select
|
||||
outlined
|
||||
dense
|
||||
label="กดปุ่มEnterเพื่อเพิ่ม"
|
||||
use-input
|
||||
use-chips
|
||||
|
|
|
|||
|
|
@ -2,21 +2,52 @@
|
|||
import { storeToRefs } from 'pinia'
|
||||
import { useSearchDataStore } from '@/stores/searched-data'
|
||||
import { useFileInfoStore } from '@/stores/file-info-data'
|
||||
import { useTreeDataStore } from '@/stores/tree-data'
|
||||
|
||||
import DialogDelete from './DialogDelete.vue'
|
||||
import UploadExistDialog from './UploadExistDialog.vue'
|
||||
import FileForm from './FileForm.vue'
|
||||
import FileItemAction from '@/components/FileItemAction.vue'
|
||||
import FileIcon from '@/components/FileIcon.vue'
|
||||
|
||||
import type { QTableProps } from 'quasar'
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
|
||||
defineProps<{
|
||||
viewMode: 'view_list' | 'view_module'
|
||||
}>()
|
||||
|
||||
const { foundFile } = storeToRefs(useSearchDataStore())
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
action: boolean
|
||||
viewMode: 'view_list' | 'view_module'
|
||||
}>(),
|
||||
{
|
||||
action: false,
|
||||
},
|
||||
)
|
||||
const { foundFile, isActFoundFile } = storeToRefs(useSearchDataStore())
|
||||
const { getFileInfo, getSize, getType } = useFileInfoStore()
|
||||
const { updateFile, deleteFile, checkFile } = useTreeDataStore()
|
||||
const keywordList = ref<string[]>([])
|
||||
const categoryList = ref<string[]>([])
|
||||
const selectKeyword = ref<string[]>([])
|
||||
const selectCategory = ref<string[]>([])
|
||||
const filterFoundFile = ref<any>()
|
||||
|
||||
const fileExistNotification = ref<boolean>(false)
|
||||
const fileFormError = ref<{ fileExist?: boolean }>({})
|
||||
const deleteFormType = ref<'deleteFile'>('deleteFile')
|
||||
const dialogDeleteState = ref<boolean>(false)
|
||||
const deleteFormPath = ref<string>('')
|
||||
|
||||
const fileFormType = ref<'edit'>('edit')
|
||||
const fileFormState = ref<boolean>(false)
|
||||
const fileFormPath = ref<string>('')
|
||||
const fileFormData = ref<{
|
||||
file?: File
|
||||
title?: string
|
||||
description?: string
|
||||
keyword?: string[]
|
||||
category?: string[]
|
||||
}>({})
|
||||
|
||||
const columns: QTableProps['columns'] = [
|
||||
{
|
||||
name: 'name',
|
||||
|
|
@ -53,6 +84,82 @@ const columns: QTableProps['columns'] = [
|
|||
},
|
||||
]
|
||||
|
||||
const currentParam = ref<Parameters<typeof submitFileForm>[0]>()
|
||||
|
||||
async function submitFileForm(
|
||||
value: {
|
||||
mode: 'create' | 'edit'
|
||||
file?: File
|
||||
title: string
|
||||
description: string
|
||||
keyword: string[]
|
||||
category: string[]
|
||||
},
|
||||
force = false,
|
||||
) {
|
||||
currentParam.value = value
|
||||
if (value.file && checkFile(value.file.name) && !force) {
|
||||
fileExistNotification.value = true
|
||||
return
|
||||
}
|
||||
|
||||
if (value.mode === 'edit') {
|
||||
await updateFile(
|
||||
fileFormPath.value,
|
||||
{
|
||||
title: value.title,
|
||||
description: value.description,
|
||||
keyword: value.keyword,
|
||||
category: value.category,
|
||||
},
|
||||
value.file,
|
||||
)
|
||||
setTimeout(() => {
|
||||
isActFoundFile.value = true
|
||||
}, 300)
|
||||
}
|
||||
|
||||
fileFormData.value = {}
|
||||
fileFormState.value = false
|
||||
currentParam.value = undefined
|
||||
}
|
||||
|
||||
function triggerFileEdit(
|
||||
value: {
|
||||
title: string
|
||||
description: string
|
||||
keyword: string[]
|
||||
category: string[]
|
||||
},
|
||||
pathname: string,
|
||||
) {
|
||||
fileFormState.value = true
|
||||
fileFormType.value = 'edit'
|
||||
fileFormPath.value = pathname
|
||||
fileFormData.value = {
|
||||
title: value.title,
|
||||
description: value.description,
|
||||
keyword: value.keyword,
|
||||
category: value.category,
|
||||
}
|
||||
}
|
||||
|
||||
function triggerFileDelete(pathname: string) {
|
||||
deleteFormType.value = 'deleteFile'
|
||||
deleteFormPath.value = pathname
|
||||
dialogDeleteState.value = !dialogDeleteState.value
|
||||
}
|
||||
|
||||
function confirmDelete() {
|
||||
if (deleteFormType) {
|
||||
deleteFile(deleteFormPath.value)
|
||||
|
||||
setTimeout(() => {
|
||||
isActFoundFile.value = true
|
||||
}, 300)
|
||||
}
|
||||
}
|
||||
|
||||
function filterSearch() {
|
||||
function updateList() {
|
||||
keywordList.value = []
|
||||
|
|
@ -101,7 +208,7 @@ onMounted(() => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="row grid q-pt-md q-gutter-sm">
|
||||
<div class="row grid q-py-md q-gutter-sm">
|
||||
<q-select
|
||||
outlined
|
||||
dense
|
||||
|
|
@ -111,6 +218,7 @@ onMounted(() => {
|
|||
:options="keywordList"
|
||||
style="width: 100%"
|
||||
label="คำสำคัญ"
|
||||
class="custom-selection"
|
||||
/>
|
||||
<q-select
|
||||
outlined
|
||||
|
|
@ -124,7 +232,7 @@ onMounted(() => {
|
|||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="viewMode === 'view_list' && foundFile.length > 0">
|
||||
<div v-if="props.viewMode === 'view_list' && foundFile.length > 0">
|
||||
<div class="grid q-mt-md">
|
||||
<div v-for="(value, index) in filterFoundFile" :key="value.title">
|
||||
<div
|
||||
|
|
@ -147,6 +255,28 @@ onMounted(() => {
|
|||
:fileMimeType="value.fileType ? value.fileType : 'unknow'"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="absolute"
|
||||
style="top: 0.5rem; right: 0.5rem"
|
||||
v-if="props.action"
|
||||
>
|
||||
<file-item-action
|
||||
:nameId="value.pathname"
|
||||
@edit="
|
||||
() =>
|
||||
triggerFileEdit(
|
||||
{
|
||||
title: value.title,
|
||||
description: value.description,
|
||||
keyword: value.keyword,
|
||||
category: value.category,
|
||||
},
|
||||
value.pathname,
|
||||
)
|
||||
"
|
||||
@delete="() => triggerFileDelete(value.pathname)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="text-overflow-handle block q-px-md text-center"
|
||||
style="max-width: 100%"
|
||||
|
|
@ -158,7 +288,10 @@ onMounted(() => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="viewMode === 'view_module' && foundFile.length > 0">
|
||||
<div
|
||||
v-if="props.viewMode === 'view_module' && foundFile.length > 0"
|
||||
class="q-gutter-sm"
|
||||
>
|
||||
<q-table
|
||||
flat
|
||||
bordered
|
||||
|
|
@ -184,7 +317,7 @@ onMounted(() => {
|
|||
</q-td>
|
||||
</template>
|
||||
|
||||
<template v-slot:body-cell-actions="sizeData">
|
||||
<template v-slot:body-cell-actions="actionData">
|
||||
<q-td class="justify-center">
|
||||
<div>
|
||||
<q-icon class="q-ma-sm" name="info" size="2em" color="primary" />
|
||||
|
|
@ -193,9 +326,29 @@ onMounted(() => {
|
|||
self="center right"
|
||||
:offset="[5, 1]"
|
||||
>
|
||||
{{ getSize(sizeData.row.fileSize) }}
|
||||
{{ getSize(actionData.row.fileSize) }}
|
||||
</q-tooltip>
|
||||
</div>
|
||||
<div v-if="props.action">
|
||||
<q-btn
|
||||
flat
|
||||
color="positive"
|
||||
dense
|
||||
icon="edit"
|
||||
@click="
|
||||
() => triggerFileEdit(actionData.row, actionData.row.pathname)
|
||||
"
|
||||
id="listViewFileEdit"
|
||||
/>
|
||||
<q-btn
|
||||
flat
|
||||
color="negative"
|
||||
dense
|
||||
icon="delete"
|
||||
@click="() => triggerFileDelete(actionData.row.pathname)"
|
||||
id="listViewFileDelete"
|
||||
/>
|
||||
</div>
|
||||
</q-td>
|
||||
</template>
|
||||
</q-table>
|
||||
|
|
@ -204,6 +357,26 @@ onMounted(() => {
|
|||
<div class="q-mt-md" v-if="foundFile.length == 0">
|
||||
<span>ไม่พบรายการที่ค้นหา</span>
|
||||
</div>
|
||||
|
||||
<file-form
|
||||
:mode="fileFormType"
|
||||
:error="fileFormError"
|
||||
v-model:open="fileFormState"
|
||||
v-model:title="fileFormData.title"
|
||||
v-model:description="fileFormData.description"
|
||||
v-model:keyword="fileFormData.keyword"
|
||||
v-model:category="fileFormData.category"
|
||||
@filechange="(name: string) => (fileFormError.fileExist = checkFile(name))"
|
||||
@submit="submitFileForm"
|
||||
/>
|
||||
|
||||
<upload-exist-dialog
|
||||
v-model:notification="fileExistNotification"
|
||||
@confirm="() => currentParam && submitFileForm(currentParam, true)"
|
||||
@cancel="() => (currentParam = undefined)"
|
||||
/>
|
||||
|
||||
<dialog-delete v-model:open="dialogDeleteState" @confirm="confirmDelete" />
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
|
@ -239,4 +412,10 @@ onMounted(() => {
|
|||
.grid .box {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.justify-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ const { data, currentDept, currentPath } = storeToRefs(useTreeDataStore())
|
|||
const { createFolder, getCabinet, gotoParent, getFolder } = useTreeDataStore()
|
||||
|
||||
const viewMode = ref<'view_list' | 'view_module'>('view_list')
|
||||
const inputSearch = ref<string>()
|
||||
const props = defineProps<{
|
||||
mode: 'admin' | 'user'
|
||||
}>()
|
||||
|
|
@ -71,10 +70,12 @@ onMounted(getCabinet)
|
|||
<div
|
||||
class="q-px-md q-py-sm text-primary bg-grey-1 pointer"
|
||||
id="container-header"
|
||||
@click="() => {
|
||||
currentPath = '' ;
|
||||
getFolder(currentPath)
|
||||
}"
|
||||
@click="
|
||||
() => {
|
||||
currentPath = ''
|
||||
getFolder(currentPath)
|
||||
}
|
||||
"
|
||||
>
|
||||
<span class="block q-my-sm text-weight-bold">ตู้จัดเก็บเอกสาร</span>
|
||||
</div>
|
||||
|
|
@ -110,6 +111,7 @@ onMounted(getCabinet)
|
|||
>
|
||||
<q-icon name="arrow_back" size="1rem" color="primary" />
|
||||
</q-btn>
|
||||
<span v-if="isSearch === true">ผลการค้นหา</span>
|
||||
<q-breadcrumbs v-if="isSearch === false" active-color="primary">
|
||||
<q-breadcrumbs-el
|
||||
v-if="currentPath === '/' || !currentPath"
|
||||
|
|
@ -136,7 +138,7 @@ onMounted(getCabinet)
|
|||
/>
|
||||
</q-breadcrumbs>
|
||||
</div>
|
||||
<span v-if="isSearch === true">ผลการค้นหา</span>
|
||||
|
||||
<q-btn
|
||||
v-if="
|
||||
mode === 'admin' &&
|
||||
|
|
@ -179,7 +181,11 @@ onMounted(getCabinet)
|
|||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<file-searched :viewMode="viewMode" v-if="isSearch === true" />
|
||||
<file-searched
|
||||
:viewMode="viewMode"
|
||||
:action="props.mode === 'admin'"
|
||||
v-if="isSearch === true"
|
||||
/>
|
||||
<file-item
|
||||
:viewMode="viewMode"
|
||||
:action="props.mode === 'admin'"
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
divdivdivdivdivdiv
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
import { useSearchDataStore } from '@/stores/searched-data'
|
||||
|
||||
const { isAdvSearchCall } = storeToRefs(useSearchDataStore())
|
||||
const { isAdvSearchCall, advSearchDataRow, advSearchDataField } =
|
||||
storeToRefs(useSearchDataStore())
|
||||
const optionsField = [
|
||||
{ label: 'ชื่อเรื่อง (title)', value: 'title' },
|
||||
{ label: 'คำสำคัญ (keyword)', value: 'keyword' },
|
||||
|
|
@ -16,26 +16,6 @@ const optionsOp = [
|
|||
{ label: 'และ', value: 'AND' },
|
||||
{ label: 'หรือ', value: 'OR' },
|
||||
]
|
||||
const advSearchDataRow = ref<
|
||||
{
|
||||
op: 'AND' | 'OR'
|
||||
field: 'title' | 'keyword'
|
||||
value: string
|
||||
}[]
|
||||
>([
|
||||
{
|
||||
op: 'AND',
|
||||
field: 'title',
|
||||
value: '',
|
||||
},
|
||||
])
|
||||
const advSearchDataField = ref<{
|
||||
keyword: string
|
||||
description: string
|
||||
}>({
|
||||
keyword: '',
|
||||
description: '',
|
||||
})
|
||||
const props = defineProps<{
|
||||
searchSubmit: Function
|
||||
submitSearchData: {
|
||||
|
|
@ -50,11 +30,6 @@ const props = defineProps<{
|
|||
}
|
||||
}>()
|
||||
|
||||
defineExpose({
|
||||
advSearchDataRow,
|
||||
advSearchDataField,
|
||||
})
|
||||
|
||||
function addAdvSearchData() {
|
||||
advSearchDataRow.value.push({
|
||||
op: 'AND',
|
||||
|
|
@ -75,7 +50,7 @@ function clearAdvSearchData() {
|
|||
},
|
||||
]
|
||||
advSearchDataField.value = {
|
||||
keyword: '',
|
||||
keyword: [],
|
||||
description: '',
|
||||
}
|
||||
}
|
||||
|
|
@ -193,13 +168,17 @@ function clearAdvSearchData() {
|
|||
|
||||
<div class="row q-col-gutter-md q-pb-md">
|
||||
<div class="col-12 col-md-5">
|
||||
<q-input
|
||||
id="advSearchKeyword"
|
||||
dense
|
||||
<q-select
|
||||
outlined
|
||||
placeholder="คำสำคัญ"
|
||||
@keydown.enter.prevent="searchSubmit()"
|
||||
dense
|
||||
v-model="advSearchDataField.keyword"
|
||||
placeholder="คำสำคัญ"
|
||||
use-input
|
||||
use-chips
|
||||
multiple
|
||||
hide-dropdown-icon
|
||||
input-debounce="0"
|
||||
new-value-mode="add"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 col-md-grow">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ref, watch } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import axiosClient from '@/services/HttpService'
|
||||
|
||||
|
|
@ -10,22 +10,21 @@ import { useLoader } from '@/stores/loader'
|
|||
import AdvancedSearch from '@/modules/01_user/components/AdvancedSearch.vue'
|
||||
|
||||
const loaderStore = useLoader()
|
||||
const { isSearch, isAdvSearchCall } = storeToRefs(useSearchDataStore())
|
||||
const {
|
||||
isSearch,
|
||||
isAdvSearchCall,
|
||||
isActFoundFile,
|
||||
searchData,
|
||||
advSearchDataField,
|
||||
advSearchDataRow,
|
||||
} = storeToRefs(useSearchDataStore())
|
||||
const { getFoundFile } = useSearchDataStore()
|
||||
const advSearchComp = ref<InstanceType<typeof AdvancedSearch>>()
|
||||
const optionsField = [
|
||||
{ label: 'ชื่อเรื่อง (title)', value: 'title' },
|
||||
{ label: 'คำสำคัญ (keyword)', value: 'keyword' },
|
||||
{ label: 'หมวดหมู่ (category)', value: 'category' },
|
||||
{ label: 'เนื้อหาในไฟล์ (content)', value: 'attachment.content' },
|
||||
]
|
||||
const searchData = ref<{
|
||||
field: string
|
||||
value: string
|
||||
}>({
|
||||
field: 'title',
|
||||
value: '',
|
||||
})
|
||||
const submitSearchData = ref<{
|
||||
AND: { field: string; value: string }[]
|
||||
OR: { field: string; value: string }[]
|
||||
|
|
@ -53,9 +52,9 @@ async function searchSubmit() {
|
|||
value: searchData.value.value,
|
||||
})
|
||||
|
||||
if (isAdvSearchCall.value && advSearchComp.value) {
|
||||
const advField = advSearchComp.value.advSearchDataField
|
||||
const advRow = advSearchComp.value.advSearchDataRow
|
||||
if (isAdvSearchCall.value) {
|
||||
let advField = advSearchDataField.value
|
||||
let advRow = advSearchDataRow.value
|
||||
|
||||
advRow.forEach((d: { field: string; value: string; op: string }) => {
|
||||
if (d.field && d.value.trim() !== '') {
|
||||
|
|
@ -63,11 +62,13 @@ async function searchSubmit() {
|
|||
submitSearchData.value[op].push({ field: d.field, value: d.value })
|
||||
}
|
||||
})
|
||||
if (advField.keyword.trim() !== '') {
|
||||
submitSearchData.value.AND.push({
|
||||
field: 'keyword',
|
||||
value: advField.keyword,
|
||||
})
|
||||
if (advField.keyword.length > 0) {
|
||||
for (let i = 0; i < advField.keyword.length; i++) {
|
||||
submitSearchData.value.AND.push({
|
||||
field: 'keyword',
|
||||
value: advField.keyword[i],
|
||||
})
|
||||
}
|
||||
}
|
||||
if (advField.description.trim() !== '') {
|
||||
submitSearchData.value.AND.push({
|
||||
|
|
@ -93,6 +94,18 @@ async function searchSubmit() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => isActFoundFile.value,
|
||||
(edited) => {
|
||||
if (edited === true) {
|
||||
searchSubmit()
|
||||
setTimeout(() => {
|
||||
isActFoundFile.value = false
|
||||
}, 300)
|
||||
}
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -154,7 +167,6 @@ async function searchSubmit() {
|
|||
<div class="row items-center justify-between q-gutter-y-md q-pt-sm">
|
||||
<div class="column col-grow">
|
||||
<advanced-search
|
||||
ref="advSearchComp"
|
||||
:searchSubmit="searchSubmit"
|
||||
:submit-search-data="submitSearchData"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -2,10 +2,42 @@ import { ref } from 'vue'
|
|||
import { defineStore } from 'pinia'
|
||||
import type { EhrFile } from '@/stores/tree-data'
|
||||
|
||||
export interface searchData {
|
||||
field: string
|
||||
value: string
|
||||
}
|
||||
|
||||
export interface advSearchDataRow {
|
||||
op: 'AND' | 'OR'
|
||||
field: 'title' | 'keyword'
|
||||
value: string
|
||||
}
|
||||
|
||||
export interface advSearchDataField {
|
||||
keyword: string[]
|
||||
description: string
|
||||
}
|
||||
|
||||
export const useSearchDataStore = defineStore('searched', () => {
|
||||
const foundFile = ref<EhrFile[]>([])
|
||||
const isAdvSearchCall = ref<boolean>(false)
|
||||
const isSearch = ref<Boolean>(false)
|
||||
const isActFoundFile = ref<Boolean>(false)
|
||||
const searchData = ref<searchData>({
|
||||
field: 'title',
|
||||
value: '',
|
||||
})
|
||||
const advSearchDataRow = ref<advSearchDataRow[]>([
|
||||
{
|
||||
op: 'AND',
|
||||
field: 'title',
|
||||
value: '',
|
||||
},
|
||||
])
|
||||
const advSearchDataField = ref<advSearchDataField>({
|
||||
keyword: [],
|
||||
description: '',
|
||||
})
|
||||
|
||||
async function getFoundFile(data: EhrFile[]) {
|
||||
foundFile.value = data
|
||||
|
|
@ -15,6 +47,10 @@ export const useSearchDataStore = defineStore('searched', () => {
|
|||
foundFile,
|
||||
isSearch,
|
||||
isAdvSearchCall,
|
||||
isActFoundFile,
|
||||
searchData,
|
||||
advSearchDataRow,
|
||||
advSearchDataField,
|
||||
getFoundFile,
|
||||
}
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue