Merge branch 'development'
This commit is contained in:
commit
b19973ef87
17 changed files with 299 additions and 158 deletions
57
.github/workflows/release.yaml
vendored
57
.github/workflows/release.yaml
vendored
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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="บันทึก"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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' },
|
||||||
|
|
|
||||||
|
|
@ -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 />
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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('.'))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"version": "dev",
|
|
||||||
"builddate": "2020-01-01_00:00:00"
|
|
||||||
}
|
|
||||||
|
|
||||||
4
Services/server/src/version.json
Normal file
4
Services/server/src/version.json
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"version": "v0.0.0-dev",
|
||||||
|
"date": "2023-01-01_00:00:00"
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue