hrms-edm/Services/client/src/components/ListView.vue
2023-12-14 15:10:31 +07:00

392 lines
11 KiB
Vue

<script lang="ts" setup>
import type { QTableProps } from 'quasar'
import { computed, onMounted, ref } from 'vue'
import { storeToRefs } from 'pinia'
import api from '@/services/HttpService'
import FileIcon from '@/components/FileIcon.vue'
import DialogDelete from '@/components/DialogDelete.vue'
import FileFormWrapper from './FileFormWrapper.vue'
import FolderFormWrapper from './FolderFormWrapper.vue'
import { useFileInfoStore } from '@/stores/file-info-data'
import useStorage from '@/stores/storage'
const storageStore = useStorage()
const { folder, file, currentInfo } = storeToRefs(storageStore)
const { goto, deleteFolder, deleteFile, constructUrl } = storageStore
const { getFormatDate, getSize, getType, getFileInfo } = useFileInfoStore()
const fileFormComponent = ref<InstanceType<typeof FileFormWrapper>>()
const folderFormComponent = ref<InstanceType<typeof FolderFormWrapper>>()
const currentIcon = computed(() =>
currentInfo.value.dept === 0
? 'mdi-file-cabinet'
: currentInfo.value.dept === 1
? 'inbox'
: 'o_folder_open',
)
const TREE_LEVEL_NAME = ['ตู้เอกสาร', 'ลิ้นชัก', 'แฟ้ม', 'แฟ้มย่อย'] as const
const props = defineProps<{
mode: 'admin' | 'user'
}>()
interface ApiResponse {
size: string
}
const deleteState = ref<boolean>(false)
const open = ref<boolean>(false)
const sizefolder = ref<string>()
const deletePath = ref<string>('')
const deleteTarget = ref<'deleteFolder' | 'deleteFile'>()
const deleteMap = { deleteFolder, deleteFile }
function triggerFolderDelete(pathname: string) {
deleteTarget.value = 'deleteFolder'
deletePath.value = pathname
deleteState.value = !deleteState.value
}
function triggerFileDelete(pathname: string) {
deleteTarget.value = 'deleteFile'
deletePath.value = pathname
deleteState.value = !deleteState.value
}
function getSizeFolder(constructFolder: string) {
const src = constructFolder.split('/').filter(Boolean)
const path = src.join('/') + '/'
const res = async () => {
const response = await api.get(constructUrl(src, false) + '/size')
sizefolder.value = response.data.size
}
if (folder.value[currentInfo.value.path]) {
const idx = folder.value[currentInfo.value.path].findIndex(
(v) => v.pathname === path,
)
if (idx !== -1) {
res()
if (folder.value[currentInfo.value.path][idx].folderSize) {
if (
folder.value[currentInfo.value.path][idx].folderSize !=
sizefolder.value
) {
folder.value[currentInfo.value.path][idx].folderSize =
sizefolder.value
}
} else {
folder.value[currentInfo.value.path][idx].folderSize = sizefolder.value
}
}
return getSize(folder.value[currentInfo.value.path][idx].folderSize)
}
}
const colFolder = [
{
name: 'name',
required: true,
label: 'ชื่อ',
align: 'left',
field: 'name',
sortable: true,
},
{
name: 'createdBy',
label: 'สร้างโดย',
align: 'center',
field: 'createdBy',
sortable: true,
},
{
name: 'createdAt',
label: 'วันที่สร้าง',
align: 'center',
field: 'createdAt',
sortable: true,
},
{
name: 'actions',
align: 'center',
label: '',
field: '',
},
] satisfies QTableProps['columns']
const colFile = [
{
name: 'name',
label: 'ชื่อไฟล์',
align: 'left',
field: 'fileName',
sortable: true,
},
{
name: 'title',
label: 'ชื่อเรื่อง',
align: 'center',
field: 'title',
sortable: true,
},
{
name: 'fileType',
label: 'ประเภทของไฟล์',
align: 'center',
field: 'fileType',
sortable: true,
},
{
name: 'actions',
align: 'center',
label: '',
field: '',
},
] satisfies QTableProps['columns']
const onRowClick = ((_, row) => {
goto(row.pathname)
}) satisfies QTableProps['onRowClick']
</script>
<template>
<file-form-wrapper ref="fileFormComponent" />
<folder-form-wrapper ref="folderFormComponent" />
<dialog-delete
v-model:open="deleteState"
@confirm="() => deleteTarget && deleteMap[deleteTarget](deletePath)"
/>
<div class="q-mt-md">
<div class="q-gutter-sm">
<div
class="flex flex-break d justify-between space-between"
v-if="
currentInfo.dept >= 1 &&
currentInfo.dept < 4 &&
props.mode === 'admin'
"
>
<div>
<span class="text-h6">{{ TREE_LEVEL_NAME[currentInfo.dept] }}</span>
</div>
<div>
<q-btn
outline
push
dense
class="q-px-md q-ml-md"
type="submit"
color="primary"
icon="add"
id="listViewFolderCreate"
:label="'สร้าง' + TREE_LEVEL_NAME[currentInfo.dept]"
@click.stop="() => folderFormComponent?.triggerFolderCreate()"
/>
</div>
</div>
<q-table
flat
bordered
row-key="name"
class="cursor"
v-if="currentInfo.dept !== 4"
:pagination="{ rowsPerPage: 20 }"
:rows="folder[currentInfo.path]"
:columns="colFolder"
@row-click="onRowClick"
>
<template v-slot:body-cell-name="data">
<q-td>
<q-icon :name="currentIcon" size="2em" color="primary" />
{{ data.row.name }}
</q-td>
</template>
<template v-slot:body-cell-createdBy="data">
<q-td class="text-center">
<span class="sort-icon-offset-margin">
{{ data.row.createdBy }}
</span>
</q-td>
</template>
<template v-slot:body-cell-createdAt="data">
<q-td class="text-center">
<span class="sort-icon-offset-margin">
{{ getFormatDate(data.row.createdAt) }}
</span>
</q-td>
</template>
<template v-slot:body-cell-actions="data">
<q-td class="justify-center">
<div>
<q-icon
@click.stop="
() => {
open = !open
}
"
class="q-ma-sm"
name="o_info"
size="2em"
color="primary"
/>
<q-tooltip
:delay="1000"
anchor="center left"
self="center right"
:offset="[5, 1]"
>
{{ getSizeFolder(data.row.pathname) }}
</q-tooltip>
</div>
<div v-if="props.mode === 'admin'">
<q-btn
flat
dense
id="listViewFolderEdit"
icon="o_edit"
color="positive"
@click.stop="
folderFormComponent?.triggerFolderEdit(
data.row.name,
data.row.pathname,
)
"
/>
<q-btn
flat
dense
id="listViewFolderDelete"
color="negative"
icon="mdi-trash-can-outline"
:data-testid="data.row.name"
@click.stop="triggerFolderDelete(data.row.pathname)"
/>
</div>
</q-td>
</template>
</q-table>
</div>
</div>
<div class="q-mt-md" v-if="currentInfo.dept >= 3">
<div class="q-gutter-sm">
<div class="flex flex-break justify-between space-between">
<div><span class="text-h6">เอกสาร</span></div>
<div>
<q-btn
outline
push
dense
id="listViewFileCreate"
class="q-px-md q-ml-md"
label="สร้างเอกสาร"
type="submit"
color="primary"
icon="add"
v-if="props.mode == 'admin'"
@click.stop="() => fileFormComponent?.triggerFileCreate()"
/>
</div>
</div>
<q-table
flat
bordered
class="cursor"
row-key="name"
:rows="file[currentInfo.path]"
:columns="colFile"
:pagination="{ rowsPerPage: 20 }"
>
<template v-slot:body-cell-name="data">
<q-td
id="listViewGetFileInfo"
style="width: 50%"
@click="() => getFileInfo(data.row)"
>
<file-icon
size="list"
:fileMimeType="data.row.fileType || '-'"
:fileName="data.row.fileName || '-'"
/>
{{ data.row.fileName }}
</q-td>
</template>
<template v-slot:body-cell-title="data">
<q-td class="text-center">
<span class="sort-icon-offset-margin">{{ data.row.title }}</span>
</q-td>
</template>
<template v-slot:body-cell-fileType="data">
<q-td class="text-center">
<span class="sort-icon-offset-margin">
{{ getType(data.row.fileType, data.row.fileName) }}
</span>
</q-td>
</template>
<template v-slot:body-cell-actions="data">
<q-td class="justify-center">
<div>
<q-icon
class="q-ma-sm"
name="o_info"
size="2em"
color="primary"
/>
<q-tooltip
anchor="center left"
self="center right"
:offset="[5, 1]"
>
{{ getSize(data.row.fileSize) }}
</q-tooltip>
</div>
<div v-if="props.mode === 'admin'">
<q-btn
flat
color="positive"
dense
icon="o_edit"
@click.stop="
() =>
fileFormComponent?.triggerFileEdit(
data.row,
data.row.pathname,
)
"
id="listViewFileEdit"
/>
<q-btn
flat
dense
id="listViewFileDelete"
color="negative"
icon="mdi-trash-can-outline"
@click.stop="() => triggerFileDelete(data.row.pathname)"
/>
</div>
</q-td>
</template>
</q-table>
</div>
</div>
</template>
<style lang="scss" scoped>
.justify-center {
display: flex;
justify-content: center;
align-items: center;
}
.sort-icon-offset-margin {
margin-right: 18px;
}
.cursor {
cursor: pointer;
}
</style>