Merge branch 'development'

This commit is contained in:
Methapon2001 2024-01-11 11:25:19 +07:00
commit b19973ef87
No known key found for this signature in database
GPG key ID: 849924FEF46BD132
17 changed files with 299 additions and 158 deletions

View file

@ -1,89 +1,78 @@
name: release name: release
run-name: release ${{ github.actor }} run-name: release ${{ github.actor }}
on: on:
# push:
# tags:
# - 'v[0-9]+.[0-9]+.[0-9]+'
# tags-ignore:
# - '2.*'
# Allow run workflow manually from Action tab
workflow_dispatch: workflow_dispatch:
inputs: inputs:
IMAGE_VER: IMAGE_VER:
description: "version for build image" description: image version
type: string type: string
env: env:
REGISTRY: docker.frappet.com REGISTRY: docker.frappet.com
IMAGE_NAME: edm/core IMAGE_NAME: edm/core
DEPLOY_HOST: frappet.com DEPLOY_HOST: frappet.com
COMPOSE_PATH: /home/chamomind/docker/edm COMPOSE_PATH: /home/chamomind/docker/edm
jobs: jobs:
# act workflow_dispatch --reuse -W .github/workflows/release.yaml --input IMAGE_VER=v0.2.4-dev -s DOCKER_USER=robot\$edm+edm -s DOCKER_PASS=jJCfpfU7jfJrvb5BRbVr6Z9HbWNQWR69 -s SSH_KEY="$(< ~/.ssh/chamomind-ehr)"
# act --reuse --workflows .github/workflows/release.yaml --job release --input IMAGE_VER=v0.2.4-dev -s DOCKER_USER=robot\$edm+edm -s DOCKER_PASS=jJCfpfU7jfJrvb5BRbVr6Z9HbWNQWR69 -s SSH_KEY="$(< ~/.ssh/chamomind-ehr)"
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out code # checkout only cms is possible but I checkout all - name: Check out code
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Gen Version - name: Gen Version
id: gen_ver id: gen_ver
run: | run: |
if [[ $GITHUB_REF == 'refs/tags/'* ]]; then if [[ $GITHUB_REF == 'refs/tags/'* ]]; then
IMAGE_VER='${GITHUB_REF/refs\/tags\//}' IMAGE_VER="${GITHUB_REF##*/}"
else else
IMAGE_VER=${{ github.event.inputs.IMAGE_VER }} IMAGE_VER=${{ github.event.inputs.IMAGE_VER }}
fi fi
if [[ $IMAGE_VER == '' ]]; then if [[ $IMAGE_VER == '' ]]; then
IMAGE_VER='beta' IMAGE_VER='dev'
fi fi
echo "{\"version\":\"$IMAGE_VER\", \"builddate\":\"$(date +"%Y-%m-%d_%T")\",\"ref_name\":\"$GITHUB_REF\" }" > ./Services/server/src/ver.json echo "{\"version\":\"$IMAGE_VER\", \"date\":\"$(date +"%Y-%m-%d_%T")\",\"ref\":\"$GITHUB_REF\" }" > ./Services/server/src/version.json
cat ./Services/server/src/ver.json
echo '::set-output name=image_ver::'$IMAGE_VER echo '::set-output name=image_ver::'$IMAGE_VER
cat ./Services/server/src/version.json
- name: Debug act - name: Debug act
if: ${{ env.ACT }} if: ${{ env.ACT }}
run: | run: |
echo $GITHUB_REF echo $GITHUB_REF
echo ${{ steps.gen_ver.outputs.image_ver }} echo ${{ steps.gen_ver.outputs.image_ver }}
cat ./Services/server/src/ver.json cat ./Services/server/src/version.json
echo ${{secrets.DOCKER_USER}} echo ${{ secrets.DOCKER_USER }}
echo ${{secrets.DOCKER_PASS}} echo ${{ secrets.DOCKER_PASS }}
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v2
- name: Login in to registry - name: Login in to registry
uses: docker/login-action@v2 uses: docker/login-action@v2
with: with:
registry: ${{env.REGISTRY}} registry: ${{ env.REGISTRY }}
username: ${{secrets.DOCKER_USER}} username: ${{ secrets.DOCKER_USER }}
password: ${{secrets.DOCKER_PASS}} password: ${{ secrets.DOCKER_PASS }}
- name: Build and push docker image - name: Build and push docker image
uses: docker/build-push-action@v3 uses: docker/build-push-action@v3
with: with:
context: ./Services context: ./Services
platforms: linux/amd64 platforms: linux/amd64
push: true push: true
tags: ${{env.REGISTRY}}/${{env.IMAGE_NAME}}:${{ steps.gen_ver.outputs.image_ver }},${{env.REGISTRY}}/${{env.IMAGE_NAME}}:latest tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.gen_ver.outputs.image_ver }},${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
# this stop solve mysterious build fail next stop ?!
- name: Debug act - name: Debug act
if: ${{ env.ACT }} if: ${{ env.ACT }}
run: | run: |
echo $GITHUB_REF cat ./Services/server/src/version.json
echo ${{ steps.gen_ver.outputs.image_ver }} echo ${{ secrets.DOCKER_USER }}
cat ./Services/server/src/ver.json echo ${{ secrets.DOCKER_PASS }}
echo ${{secrets.DOCKER_USER}}
echo ${{secrets.DOCKER_PASS}}
- name: Remote Deployment - name: Remote Deployment
uses: appleboy/ssh-action@v1.0.0 uses: appleboy/ssh-action@v1.0.0
# uses: appleboy/ssh-action@v0.1.8
with: with:
host: ${{env.DEPLOY_HOST}} host: ${{ env.DEPLOY_HOST }}
username: chamomind
key: ${{ secrets.SSH_KEY }} key: ${{ secrets.SSH_KEY }}
username: chamomind
port: 10100 port: 10100
script: | script: |
cd "${{env.COMPOSE_PATH}}" cd "${{ env.COMPOSE_PATH }}"
docker compose pull docker compose pull
docker compose up -d docker compose up -d
echo "${{ steps.gen_ver.outputs.image_ver }}"> success echo "${{ steps.gen_ver.outputs.image_ver }}"> success

View file

@ -19,6 +19,7 @@ const props = withDefaults(
description?: string description?: string
keyword?: string[] keyword?: string[]
category?: string[] category?: string[]
author?: string
}>(), }>(),
{ {
open: false, open: false,
@ -34,6 +35,7 @@ const emit = defineEmits([
'update:description', 'update:description',
'update:keyword', 'update:keyword',
'update:category', 'update:category',
'update:author',
'filechange', 'filechange',
'reset', 'reset',
'submit', 'submit',
@ -56,6 +58,7 @@ function reset() {
emit('update:description', '') emit('update:description', '')
emit('update:keyword', '') emit('update:keyword', '')
emit('update:category', '') emit('update:category', '')
emit('update:author', '')
emit('reset') emit('reset')
} }
@ -67,6 +70,7 @@ function submit() {
description: props.description ?? '', description: props.description ?? '',
keyword: props.keyword, keyword: props.keyword,
category: props.category, category: props.category,
author: props.author,
}) })
} }
@ -165,7 +169,9 @@ const file = ref<File | undefined>()
: '' : ''
" "
id="inputFile" id="inputFile"
:rules="[(v) => (v !== undefined || mode === 'edit' ) || ('โปรดอัปโหลดไฟล์')]" :rules="[
(v) => v !== undefined || mode === 'edit' || 'โปรดอัปโหลดไฟล์',
]"
> >
<template v-slot:prepend> <template v-slot:prepend>
<q-icon name="attach_file" /> <q-icon name="attach_file" />
@ -181,7 +187,10 @@ const file = ref<File | undefined>()
class="q-my-sm" class="q-my-sm"
placeholder="กรอกชื่อเรื่อง" placeholder="กรอกชื่อเรื่อง"
:model-value="title" :model-value="title"
:rules="[(v) => (v != undefined && v.length > 3) || 'ชื่อต้องยาวกว่า 3 ตัวอักษร']" :rules="[
(v) =>
(v != undefined && v.length > 3) || 'ชื่อต้องยาวกว่า 3 ตัวอักษร',
]"
@update:model-value="(v) => $emit('update:title', v)" @update:model-value="(v) => $emit('update:title', v)"
id="inputTitle" id="inputTitle"
/> />
@ -217,7 +226,6 @@ const file = ref<File | undefined>()
@new-value="createCategory" @new-value="createCategory"
:options="filterDataCategory" :options="filterDataCategory"
@filter="filterCategory" @filter="filterCategory"
style="width: 250px"
@update:model-value="(v) => $emit('update:category', v)" @update:model-value="(v) => $emit('update:category', v)"
data-testid="filterDataCategory" data-testid="filterDataCategory"
> >
@ -237,7 +245,6 @@ const file = ref<File | undefined>()
multiple multiple
hide-dropdown-icon hide-dropdown-icon
input-debounce="0" input-debounce="0"
style="width: 250px"
:model-value="props.keyword" :model-value="props.keyword"
@update:model-value="(v) => $emit('update:keyword', v)" @update:model-value="(v) => $emit('update:keyword', v)"
@new-value="createKeyword" @new-value="createKeyword"
@ -247,6 +254,23 @@ const file = ref<File | undefined>()
</div> </div>
</section> </section>
<section class="q-mb-md">
<span class="text-weight-bold">เจาของผลงาน</span>
<q-input
outlined
dense
class="q-my-sm"
placeholder="เจ้าของผลงาน"
:model-value="author"
:rules="[
(v) =>
(v != undefined && v.length > 3) || 'ชื่อต้องยาวกว่า 3 ตัวอักษร',
]"
@update:model-value="(v) => $emit('update:author', v)"
id="inputAuthor"
/>
</section>
<section :style="{ display: 'flex', gap: '.5rem' }"> <section :style="{ display: 'flex', gap: '.5rem' }">
<q-btn <q-btn
label="บันทึก" label="บันทึก"

View file

@ -17,6 +17,7 @@ const fileFormData = ref<{
description?: string description?: string
keyword?: string[] keyword?: string[]
category?: string[] category?: string[]
author?: string
}>({}) }>({})
const fileFormType = ref<'edit' | 'create'>('create') const fileFormType = ref<'edit' | 'create'>('create')
const fileFormError = ref<{ fileExist?: boolean; fileName2Long?: boolean }>({}) const fileFormError = ref<{ fileExist?: boolean; fileName2Long?: boolean }>({})
@ -36,6 +37,7 @@ function triggerFileEdit(
description: string description: string
keyword: string[] keyword: string[]
category: string[] category: string[]
author: string
}, },
pathname: string, pathname: string,
file?: string, file?: string,
@ -48,6 +50,7 @@ function triggerFileEdit(
description: value.description, description: value.description,
keyword: value.keyword, keyword: value.keyword,
category: value.category, category: value.category,
author: value.author,
} }
fileNameLabel.value = file fileNameLabel.value = file
} }
@ -68,7 +71,7 @@ function checkFileExist(name: string, except?: string) {
} }
function checkFileName2Long(name: string, except?: string) { function checkFileName2Long(name: string, except?: string) {
return Boolean(name.length > 85) return name !== except && Boolean(name.length > 85)
} }
async function submitFileForm( async function submitFileForm(
@ -79,6 +82,7 @@ async function submitFileForm(
description: string description: string
keyword: string[] keyword: string[]
category: string[] category: string[]
author: string
}, },
force = false, force = false,
) { ) {
@ -101,6 +105,7 @@ async function submitFileForm(
description: value.description, description: value.description,
keyword: value.keyword, keyword: value.keyword,
category: value.category, category: value.category,
author: value.author,
}) })
} else { } else {
await updateFile( await updateFile(
@ -110,6 +115,7 @@ async function submitFileForm(
description: value.description, description: value.description,
keyword: value.keyword, keyword: value.keyword,
category: value.category, category: value.category,
author: value.author,
}, },
value.file, value.file,
) )
@ -132,11 +138,15 @@ async function submitFileForm(
v-model:description="fileFormData.description" v-model:description="fileFormData.description"
v-model:keyword="fileFormData.keyword" v-model:keyword="fileFormData.keyword"
v-model:category="fileFormData.category" v-model:category="fileFormData.category"
v-model:author="fileFormData.author"
@reset="() => (fileFormError = {})" @reset="() => (fileFormError = {})"
@filechange=" @filechange="
(name: string) => { (name: string) => {
;(fileFormError.fileExist = checkFileExist(name, fileNameLabel)), ;(fileFormError.fileExist = checkFileExist(name, fileNameLabel)),
(fileFormError.fileName2Long = checkFileName2Long(name, fileNameLabel)) (fileFormError.fileName2Long = checkFileName2Long(
name,
fileNameLabel,
))
} }
" "
@submit="submitFileForm" @submit="submitFileForm"

View file

@ -246,6 +246,7 @@ function triggerFileDelete(pathname: string) {
description: value.description, description: value.description,
keyword: value.keyword, keyword: value.keyword,
category: value.category, category: value.category,
author: value.author,
}, },
value.pathname, value.pathname,
value.fileName, value.fileName,

View file

@ -29,6 +29,9 @@ const { getFileInfo, getSize, getType } = useFileInfoStore()
const storageStore = useStorage() const storageStore = useStorage()
const { deleteFile } = storageStore const { deleteFile } = storageStore
const fileInfoStore = useFileInfoStore()
const { getFormatDate } = fileInfoStore
const fileFormComponent = ref<InstanceType<typeof FileFormWrapper>>() const fileFormComponent = ref<InstanceType<typeof FileFormWrapper>>()
const keywordList = ref<string[]>([]) const keywordList = ref<string[]>([])
@ -54,12 +57,20 @@ const columns: QTableProps['columns'] = [
}, },
{ {
name: 'title', name: 'title',
align: 'center', align: 'left',
label: 'ชื่อเรื่อง', label: 'ชื่อเรื่อง',
field: 'title', field: 'title',
style: 'width: 200px', style: 'width: 200px',
sortable: true, sortable: true,
}, },
{
name: 'author',
align: 'left',
label: 'เจ้าของผลงาน',
field: 'author',
style: 'width: 200px',
sortable: true,
},
{ {
name: 'fileType', name: 'fileType',
align: 'center', align: 'center',
@ -223,6 +234,7 @@ onMounted(() => {
description: value.description, description: value.description,
keyword: value.keyword, keyword: value.keyword,
category: value.category, category: value.category,
author: value.author,
}, },
value.pathname, value.pathname,
value.fileName, value.fileName,
@ -262,17 +274,29 @@ onMounted(() => {
<file-icon <file-icon
size="list" size="list"
:fileMimeType=" :fileMimeType="
nameData.row.fileType ? nameData.row.fileType : 'unknow' nameData.row.fileType ? nameData.row.fileType : 'unknown'
"
:fileName="
nameData.row.fileName ? nameData.row.fileName : 'unknown'
" "
:fileName="nameData.row.fileName ? nameData.row.fileName : 'unknow'"
/> />
{{ nameData.row.fileName }} {{ nameData.row.fileName }}
</q-td> </q-td>
</template> </template>
<template v-slot:body-cell-title="data">
<q-td style="width: 50%" @click="() => getFileInfo(data.row)">
{{ data.row.metadata.subject ?? data.row.title }}
</q-td>
</template>
<template v-slot:body-cell-author="author">
<q-td style="width: 50%" @click="() => getFileInfo(author.row)">
{{ author.row.metadata.author ?? author.row.author }}
</q-td>
</template>
<template v-slot:body-cell-fileType="typeData"> <template v-slot:body-cell-fileType="typeData">
<q-td> <q-td>
<div class="justify-center"> <div>
{{ getType(typeData.row.fileType, typeData.row.fileName) }} {{ getType(typeData.row.fileType, typeData.row.fileName) }}
</div> </div>
</q-td> </q-td>
@ -282,12 +306,29 @@ onMounted(() => {
<q-td class="justify-center"> <q-td class="justify-center">
<div> <div>
<q-icon class="q-ma-sm" name="o_info" size="2em" color="primary" /> <q-icon class="q-ma-sm" name="o_info" size="2em" color="primary" />
<q-tooltip <q-tooltip anchor="center left" self="center right">
anchor="center left" <div class="flex" style="flex-direction: column; font-size: 120%">
self="center right" <span>อไฟล: {{ actionData.row.fileName }}</span>
:offset="[5, 1]" <span>
> อเรอง:
{{ getSize(actionData.row.fileSize) }} {{ actionData.row.metadata.subject ?? actionData.row.title }}
</span>
<span>
เจาของผลงาน:
{{ actionData.row.metadata.author ?? actionData.row.author }}
</span>
<span>ขนาด: {{ getSize(actionData.row.fileSize) }}</span>
<span>
ประเภทของไฟล:
{{
getType(actionData.row.fileType, actionData.row.fileName)
}}
</span>
<span>
นทปโหลด:
{{ getFormatDate(actionData.row.createdAt) }}
</span>
</div>
</q-tooltip> </q-tooltip>
</div> </div>
<div v-if="props.action"> <div v-if="props.action">

View file

@ -35,7 +35,6 @@ const props = defineProps<{
const deleteState = ref<boolean>(false) const deleteState = ref<boolean>(false)
const open = ref<boolean>(false) const open = ref<boolean>(false)
const deletePath = ref<string>('') const deletePath = ref<string>('')
const deleteTarget = ref<'deleteFolder' | 'deleteFile'>() const deleteTarget = ref<'deleteFolder' | 'deleteFile'>()
const deleteMap = { deleteFolder, deleteFile } const deleteMap = { deleteFolder, deleteFile }
@ -90,14 +89,14 @@ const colFolder = [
{ {
name: 'createdBy', name: 'createdBy',
label: 'สร้างโดย', label: 'สร้างโดย',
align: 'center', align: 'left',
field: 'createdBy', field: 'createdBy',
sortable: true, sortable: true,
}, },
{ {
name: 'createdAt', name: 'createdAt',
label: 'วันที่สร้าง', label: 'วันที่สร้าง',
align: 'center', align: 'left',
field: 'createdAt', field: 'createdAt',
sortable: true, sortable: true,
}, },
@ -120,14 +119,22 @@ const colFile = [
{ {
name: 'title', name: 'title',
label: 'ชื่อเรื่อง', label: 'ชื่อเรื่อง',
align: 'center', align: 'left',
field: 'title', field: 'title',
sortable: true, sortable: true,
}, },
{
name: 'author',
align: 'left',
label: 'เจ้าของผลงาน',
field: 'author',
style: 'width: 200px',
sortable: true,
},
{ {
name: 'fileType', name: 'fileType',
label: 'ประเภทของไฟล์', label: 'ประเภทของไฟล์',
align: 'center', align: 'left',
field: 'fileType', field: 'fileType',
sortable: true, sortable: true,
}, },
@ -197,14 +204,14 @@ const onRowClick = ((_, row) => {
</q-td> </q-td>
</template> </template>
<template v-slot:body-cell-createdBy="data"> <template v-slot:body-cell-createdBy="data">
<q-td class="text-center"> <q-td>
<span class="sort-icon-offset-margin"> <span class="sort-icon-offset-margin">
{{ data.row.createdBy }} {{ data.row.createdBy }}
</span> </span>
</q-td> </q-td>
</template> </template>
<template v-slot:body-cell-createdAt="data"> <template v-slot:body-cell-createdAt="data">
<q-td class="text-center"> <q-td>
<span class="sort-icon-offset-margin"> <span class="sort-icon-offset-margin">
{{ getFormatDate(data.row.createdAt) }} {{ getFormatDate(data.row.createdAt) }}
</span> </span>
@ -306,12 +313,21 @@ const onRowClick = ((_, row) => {
</q-td> </q-td>
</template> </template>
<template v-slot:body-cell-title="data"> <template v-slot:body-cell-title="data">
<q-td class="text-center"> <q-td>
<span class="sort-icon-offset-margin">{{ data.row.title }}</span> <span class="sort-icon-offset-margin">{{
data.row.metadata.subject ?? data.row.title
}}</span>
</q-td>
</template>
<template v-slot:body-cell-author="data">
<q-td>
<span class="sort-icon-offset-margin">
{{ data.row.metadata.author ?? data.row.author }}
</span>
</q-td> </q-td>
</template> </template>
<template v-slot:body-cell-fileType="data"> <template v-slot:body-cell-fileType="data">
<q-td class="text-center"> <q-td>
<span class="sort-icon-offset-margin"> <span class="sort-icon-offset-margin">
{{ getType(data.row.fileType, data.row.fileName) }} {{ getType(data.row.fileType, data.row.fileName) }}
</span> </span>
@ -326,12 +342,30 @@ const onRowClick = ((_, row) => {
size="2em" size="2em"
color="primary" color="primary"
/> />
<q-tooltip <q-tooltip anchor="center left" self="center right">
anchor="center left" <div
self="center right" class="flex"
:offset="[5, 1]" style="flex-direction: column; font-size: 120%"
> >
{{ getSize(data.row.fileSize) }} <span>อไฟล: {{ data.row.fileName }}</span>
<span>
อเรอง:
{{ data.row.metadata.subject ?? data.row.title }}
</span>
<span>
เจาของผลงาน:
{{ data.row.metadata.author ?? data.row.author }}
</span>
<span>ขนาด: {{ getSize(data.row.fileSize) }}</span>
<span>
ประเภทของไฟล:
{{ getType(data.row.fileType, data.row.fileName) }}
</span>
<span>
นทปโหลด:
{{ getFormatDate(data.row.createdAt) }}
</span>
</div>
</q-tooltip> </q-tooltip>
</div> </div>
<div v-if="props.mode === 'admin'"> <div v-if="props.mode === 'admin'">
@ -373,11 +407,21 @@ const onRowClick = ((_, row) => {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.justify-center {
display: flex;
justify-content: center;
align-items: center;
}
.sort-icon-offset-margin { .sort-icon-offset-margin {
margin-right: 18px; margin-right: 18px;
} }
.q-item-label {
text-align: left;
}
.underline {
text-decoration: underline;
}
.cursor { .cursor {
cursor: pointer; cursor: pointer;
} }

View file

@ -108,9 +108,9 @@ const folderFormComponent = ref<InstanceType<typeof FolderFormWrapper>>()
<span v-if="isSearch"> <span v-if="isSearch">
ผลการคนหา ผลการคนหา
<span class="text-grey text-body2 q-ml-md">{{ <span class="text-grey text-body2 q-ml-md">{{
mode === 'admin' && mode === 'admin' && currentInfo.path !== '/'
currentInfo.path !== '/' && ? currentInfo.path.split('/').join(' / ')
currentInfo.path.split('/').join(' / ') : ''
}}</span> }}</span>
</span> </span>
<q-breadcrumbs <q-breadcrumbs

View file

@ -3,14 +3,8 @@ import { storeToRefs } from 'pinia'
import { useSearchDataStore } from '@/stores/searched-data' import { useSearchDataStore } from '@/stores/searched-data'
const { isAdvSearchCall, advSearchDataRow, advSearchDataField } = const { isAdvSearchCall, advSearchDataRow, advSearchDataField, optionsField } =
storeToRefs(useSearchDataStore()) storeToRefs(useSearchDataStore())
const optionsField = [
{ label: 'ชื่อเรื่อง (title)', value: 'title' },
{ label: 'คำสำคัญ (keyword)', value: 'keyword' },
{ label: 'หมวดหมู่ (category)', value: 'category' },
{ label: 'เนื้อหาในไฟล์ (content)', value: 'attachment.content' },
]
const optionsOp = [ const optionsOp = [
{ label: 'และ', value: 'AND' }, { label: 'และ', value: 'AND' },
{ label: 'หรือ', value: 'OR' }, { label: 'หรือ', value: 'OR' },

View file

@ -132,7 +132,7 @@ async function downloadSubmit(path: string | undefined) {
<span>อเรอง</span> <span>อเรอง</span>
</div> </div>
<div class="col-grow"> <div class="col-grow">
<span class="text-grey">{{ fileInfo?.title }}</span> <span class="text-grey">{{ fileInfo?.metadata.subject ?? fileInfo?.title }}</span>
</div> </div>
</div> </div>
<q-separator /> <q-separator />
@ -147,10 +147,10 @@ async function downloadSubmit(path: string | undefined) {
<q-separator /> <q-separator />
<div class="row"> <div class="row">
<div class="col-12 col-md-3"> <div class="col-12 col-md-3">
<span>เข</span> <span>เจาของผลงา</span>
</div> </div>
<div class="col-grow"> <div class="col-grow">
<span class="text-grey">{{ fileInfo?.author }}</span> <span class="text-grey">{{ fileInfo?.metadata.author ?? fileInfo?.author }}</span>
</div> </div>
</div> </div>
<q-separator /> <q-separator />

View file

@ -22,15 +22,10 @@ const {
isAdvSearchCall, isAdvSearchCall,
searchData, searchData,
advSearchDataField, advSearchDataField,
optionsField,
advSearchDataRow, advSearchDataRow,
} = storeToRefs(useSearchDataStore()) } = storeToRefs(useSearchDataStore())
const { getFoundFile } = useSearchDataStore() const { getFoundFile } = useSearchDataStore()
const optionsField = [
{ label: 'ชื่อเรื่อง (title)', value: 'title' },
{ label: 'คำสำคัญ (keyword)', value: 'keyword' },
{ label: 'หมวดหมู่ (category)', value: 'category' },
{ label: 'เนื้อหาในไฟล์ (content)', value: 'attachment.content' },
]
const submitSearchData = ref<{ const submitSearchData = ref<{
AND: { AND: {
field: string field: string
@ -55,7 +50,7 @@ async function submitSearch() {
if (searchData.value.value.trim() !== '') { if (searchData.value.value.trim() !== '') {
submitSearchData.value = { AND: [], OR: [] } submitSearchData.value = { AND: [], OR: [] }
if (props.mode === 'admin') { if (props.mode === 'admin') {
optionsField.forEach((option) => { optionsField.value.forEach((option) => {
submitSearchData.value.OR.push({ submitSearchData.value.OR.push({
field: option.value, field: option.value,
value: searchData.value.value, value: searchData.value.value,
@ -67,6 +62,16 @@ async function submitSearch() {
value: searchData.value.value, value: searchData.value.value,
exact: true, exact: true,
}) })
submitSearchData.value.OR.push({
field: 'metadata.author',
value: searchData.value.value,
exact: true,
})
submitSearchData.value.OR.push({
field: 'metadata.subject',
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) || '',
@ -79,6 +84,20 @@ async function submitSearch() {
}) })
} }
} else { } else {
if (searchData.value.field == 'title') {
submitSearchData.value.OR.push({
field: 'metadata.subject',
value: searchData.value.value,
exact: isExact.value,
})
}
if (searchData.value.field == 'author') {
submitSearchData.value.OR.push({
field: 'metadata.author',
value: searchData.value.value,
exact: isExact.value,
})
}
submitSearchData.value.OR.push({ submitSearchData.value.OR.push({
field: searchData.value.field, field: searchData.value.field,
value: searchData.value.value, value: searchData.value.value,
@ -92,6 +111,20 @@ async function submitSearch() {
(d: { field: string; value: string; op: string; exact: boolean }) => { (d: { field: string; value: string; op: string; exact: boolean }) => {
if (d.field && d.value.trim() !== '') { if (d.field && d.value.trim() !== '') {
const op = d.op === 'AND' ? 'AND' : 'OR' const op = d.op === 'AND' ? 'AND' : 'OR'
if (d.field == 'title') {
submitSearchData.value[op].push({
field: 'metadata.subject',
value: d.value,
exact: d.exact,
})
}
if (d.field == 'author') {
submitSearchData.value[op].push({
field: 'metadata.author',
value: d.value,
exact: d.exact,
})
}
submitSearchData.value[op].push({ submitSearchData.value[op].push({
field: d.field, field: d.field,
value: d.value, value: d.value,
@ -125,7 +158,6 @@ 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) {
@ -218,9 +250,7 @@ watch(
<div class="col"> <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="col-grow"> <div class="col-grow">
<advanced-search <advanced-search :submitSearch="submitSearch" />
:submitSearch="submitSearch"
/>
</div> </div>
<div v-if="isAdvSearchCall === false"> <div v-if="isAdvSearchCall === false">
<q-btn <q-btn

View file

@ -67,7 +67,7 @@ export const useFileInfoStore = defineStore('info', () => {
const extension = mime.getExtension(mimeType) const extension = mime.getExtension(mimeType)
if (extension) return '.' + extension if (extension) return extension
if (fileName && fileName.includes('.')) { if (fileName && fileName.includes('.')) {
return fileName.substring(fileName.lastIndexOf('.')) return fileName.substring(fileName.lastIndexOf('.'))
} }

View file

@ -36,6 +36,13 @@ export const useSearchDataStore = defineStore('searched', () => {
exact: false, exact: false,
}, },
]) ])
const optionsField = ref([
{ label: 'ชื่อเรื่อง (title)', value: 'title' },
{ label: 'คำสำคัญ (keyword)', value: 'keyword' },
{ label: 'หมวดหมู่ (category)', value: 'category' },
{ label: 'เนื้อหาในไฟล์ (content)', value: 'attachment.content' },
{ label: 'เจ้าของผลงาน (author)', value: 'author' },
])
const advSearchDataField = ref<AdvancedSearchFields>({ const advSearchDataField = ref<AdvancedSearchFields>({
keyword: [], keyword: [],
description: '', description: '',
@ -52,6 +59,7 @@ export const useSearchDataStore = defineStore('searched', () => {
isAdvSearchCall, isAdvSearchCall,
searchData, searchData,
advSearchDataRow, advSearchDataRow,
optionsField,
advSearchDataField, advSearchDataField,
getFoundFile, getFoundFile,
} }

View file

@ -26,7 +26,7 @@ export interface StorageFile {
fileType: string fileType: string
title: string title: string
description: string description: string
author: string, author: string
metadata: Record<string, unknown> metadata: Record<string, unknown>
category: string[] category: string[]
keyword: string[] keyword: string[]
@ -393,6 +393,7 @@ const useStorage = defineStore('storageStore', () => {
description?: string description?: string
category?: string[] category?: string[]
keyword?: string[] keyword?: string[]
author?: string
} }
async function createFile( async function createFile(
file: File, file: File,
@ -441,9 +442,9 @@ const useStorage = defineStore('storageStore', () => {
}, },
to: file?.name to: file?.name
? { ? {
file: file.name, file: file.name,
path: arr, path: arr,
} }
: undefined, : undefined,
upload: !!file, upload: !!file,
}, },

View file

@ -430,7 +430,7 @@ export class StorageController extends Controller {
*/ */
@Post("folder/size") @Post("folder/size")
@Tags("Storage Folder") @Tags("Storage Folder")
@Security("bearerAuth", ["management-role", "admin"]) @Security("bearerAuth")
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ") @SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
@Example({ @Example({
size: 10240, size: 10240,

View file

@ -1,5 +1,5 @@
import { Controller, Get, Route, Tags } from "tsoa"; import { Controller, Get, Route, Tags } from "tsoa";
import version from "../ver.json"; import version from "../version.json";
@Route("version") @Route("version")
export class VersionController extends Controller { export class VersionController extends Controller {

View file

@ -1,5 +0,0 @@
{
"version": "dev",
"builddate": "2020-01-01_00:00:00"
}

View file

@ -0,0 +1,4 @@
{
"version": "v0.0.0-dev",
"date": "2023-01-01_00:00:00"
}