Merge branch 'net' into development

This commit is contained in:
somnetsak123 2023-12-14 15:11:12 +07:00
commit e65fb9f5d9
2 changed files with 139 additions and 44 deletions

View file

@ -1,19 +1,19 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { QTableProps } from 'quasar' import type { QTableProps } from 'quasar'
import { computed, ref } from 'vue' import { computed, onMounted, ref } from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import api from '@/services/HttpService'
import FileIcon from '@/components/FileIcon.vue' import FileIcon from '@/components/FileIcon.vue'
import DialogDelete from '@/components/DialogDelete.vue' import DialogDelete from '@/components/DialogDelete.vue'
import FileFormWrapper from './FileFormWrapper.vue' import FileFormWrapper from './FileFormWrapper.vue'
import FolderFormWrapper from './FolderFormWrapper.vue' import FolderFormWrapper from './FolderFormWrapper.vue'
import { useFileInfoStore } from '@/stores/file-info-data' import { useFileInfoStore } from '@/stores/file-info-data'
import useStorage from '@/stores/storage' import useStorage from '@/stores/storage'
const storageStore = useStorage() const storageStore = useStorage()
const { folder, file, currentInfo } = storeToRefs(storageStore) const { folder, file, currentInfo } = storeToRefs(storageStore)
const { goto, deleteFolder, deleteFile } = storageStore const { goto, deleteFolder, deleteFile, constructUrl } = storageStore
const { getFormatDate, getSize, getType, getFileInfo } = useFileInfoStore() const { getFormatDate, getSize, getType, getFileInfo } = useFileInfoStore()
@ -33,7 +33,14 @@ const props = defineProps<{
mode: 'admin' | 'user' mode: 'admin' | 'user'
}>() }>()
interface ApiResponse {
size: string
}
const deleteState = ref<boolean>(false) const deleteState = ref<boolean>(false)
const open = ref<boolean>(false)
const sizefolder = ref<string>()
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 }
@ -50,6 +57,37 @@ function triggerFileDelete(pathname: string) {
deleteState.value = !deleteState.value 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 = [ const colFolder = [
{ {
name: 'name', name: 'name',
@ -186,18 +224,23 @@ const onRowClick = ((_, row) => {
<q-td class="justify-center"> <q-td class="justify-center">
<div> <div>
<q-icon <q-icon
@click.stop @click.stop="
() => {
open = !open
}
"
class="q-ma-sm" class="q-ma-sm"
name="o_info" name="o_info"
size="2em" size="2em"
color="primary" color="primary"
/> />
<q-tooltip <q-tooltip
:delay="1000"
anchor="center left" anchor="center left"
self="center right" self="center right"
:offset="[5, 1]" :offset="[5, 1]"
> >
{{ data.row.name }} {{ getSizeFolder(data.row.pathname) }}
</q-tooltip> </q-tooltip>
</div> </div>
<div v-if="props.mode === 'admin'"> <div v-if="props.mode === 'admin'">
@ -312,7 +355,6 @@ const onRowClick = ((_, row) => {
fileFormComponent?.triggerFileEdit( fileFormComponent?.triggerFileEdit(
data.row, data.row,
data.row.pathname, data.row.pathname,
data.row.fileName,
) )
" "
id="listViewFileEdit" id="listViewFileEdit"

View file

@ -13,6 +13,7 @@ type Path = string
export interface StorageFolder { export interface StorageFolder {
pathname: string pathname: string
name: string name: string
folderSize?: string
createdAt: string createdAt: string
createdBy: string createdBy: string
} }
@ -58,6 +59,7 @@ function constructUrl(path: string | string[], append = true) {
return a return a
} }
}, '') }, '')
return append return append
? url + ['cabinet', '/drawer', '/folder', '/subfolder'][arr.length] ? url + ['cabinet', '/drawer', '/folder', '/subfolder'][arr.length]
: url : url
@ -137,7 +139,13 @@ const useStorage = defineStore('storageStore', () => {
if (arr.length >= 4) return // this system does not have more than 4 level if (arr.length >= 4) return // this system does not have more than 4 level
const res = await api.get<(typeof folder.value)[string]>(constructUrl(arr)) const res = await api.post<(typeof folder.value)[string]>(
`${import.meta.env.VITE_API_ENDPOINT}storage/list`,
{
operation: 'folder',
path: arr,
},
)
if (res.status === 200 && res.data && Array.isArray(res.data)) if (res.status === 200 && res.data && Array.isArray(res.data))
folder.value[consistantPath(path)] = res.data.sort((a, b) => folder.value[consistantPath(path)] = res.data.sort((a, b) =>
a.pathname.localeCompare(b.pathname), a.pathname.localeCompare(b.pathname),
@ -149,8 +157,12 @@ const useStorage = defineStore('storageStore', () => {
if (arr.length < 3) return // file in this system only lives in level 3 and 4 if (arr.length < 3) return // file in this system only lives in level 3 and 4
const res = await api.get<(typeof file.value)[string]>( const res = await api.post<(typeof file.value)[string]>(
constructUrl(arr, false) + '/file', `${import.meta.env.VITE_API_ENDPOINT}storage/list`,
{
operation: 'file',
path: arr,
},
) )
if (res.status === 200 && res.data && Array.isArray(res.data)) if (res.status === 200 && res.data && Array.isArray(res.data))
file.value[consistantPath(path)] = res.data.sort((a, b) => file.value[consistantPath(path)] = res.data.sort((a, b) =>
@ -192,7 +204,7 @@ const useStorage = defineStore('storageStore', () => {
socket.on('connect', () => console.info('Socket.io connected.')) socket.on('connect', () => console.info('Socket.io connected.'))
socket.on('disconnect', () => console.info('Socket.io disconnected.')) socket.on('disconnect', () => console.info('Socket.io disconnected.'))
socket.on( socket.on(
'CreateFolder', 'FolderCreate',
(data: { (data: {
pathname: string pathname: string
name: string name: string
@ -222,7 +234,7 @@ const useStorage = defineStore('storageStore', () => {
// NOTE: // NOTE:
// API planned to make new endpoint that can move and rename in one go. // API planned to make new endpoint that can move and rename in one go.
// Need to change if api handle move and rename file instead of just edit. // Need to change if api handle move and rename file instead of just edit.
socket.on('EditFolder', (data: { from: string; to: string }) => { socket.on('FolderMove', (data: { from: string; to: string }) => {
const src = data.from.split('/').filter(Boolean) const src = data.from.split('/').filter(Boolean)
const dst = data.to.split('/').filter(Boolean) const dst = data.to.split('/').filter(Boolean)
const path = consistantPath(src.slice(0, -1)) const path = consistantPath(src.slice(0, -1))
@ -259,7 +271,7 @@ const useStorage = defineStore('storageStore', () => {
} }
} }
}) })
socket.on('DeleteFolder', (data: { pathname: string }) => { socket.on('FolderDelete', (data: { pathname: string }) => {
for (let key in folder.value) { for (let key in folder.value) {
if (key.startsWith(data.pathname)) { if (key.startsWith(data.pathname)) {
delete folder.value[key] delete folder.value[key]
@ -315,20 +327,17 @@ const useStorage = defineStore('storageStore', () => {
) )
} }
}) })
socket.on( socket.on('FileMove', (data: { from: StorageFile; to: StorageFile }) => {
'FileUpdateMove', const arr = data.from.pathname.split('/').filter(Boolean)
(data: { from: StorageFile; to: StorageFile }) => { const path = consistantPath(arr.slice(0, -1))
const arr = data.from.pathname.split('/').filter(Boolean)
const path = consistantPath(arr.slice(0, -1))
if (file.value[path]) { if (file.value[path]) {
const idx = file.value[path].findIndex( const idx = file.value[path].findIndex(
(v) => v.pathname === data.from.pathname, (v) => v.pathname === data.from.pathname,
) )
if (idx !== -1) file.value[path][idx] = data.to if (idx !== -1) file.value[path][idx] = data.to
} }
}, })
)
socket.on('FileUpdate', (data: StorageFile) => { socket.on('FileUpdate', (data: StorageFile) => {
const arr = data.pathname.split('/').filter(Boolean) const arr = data.pathname.split('/').filter(Boolean)
const path = consistantPath(arr.slice(0, -1)) const path = consistantPath(arr.slice(0, -1))
@ -367,42 +376,67 @@ const useStorage = defineStore('storageStore', () => {
msg: `พบชื่อ \"${name}\" ซ้ำในระบบ`, msg: `พบชื่อ \"${name}\" ซ้ำในระบบ`,
}) })
} else { } else {
await api.post(constructUrl(path, true), { name }) const arrayPath: string[] = path.split('/').filter(Boolean)
await api.post(`${import.meta.env.VITE_API_ENDPOINT}storage/folder`, {
path: arrayPath,
name: name,
})
} }
loader.hide() loader.hide()
} }
async function editFolder(name: string, path: string) { async function editFolder(name: string, path: string) {
loader.show() loader.show()
await api.put(constructUrl(path, false), { name }) const arrayPath: string[] = path.split('/').filter(Boolean)
const beforeName = arrayPath.pop()
await api.put(`${import.meta.env.VITE_API_ENDPOINT}storage/folder`, {
from: {
name: beforeName,
path: arrayPath,
},
to: {
name: name,
path: arrayPath,
},
})
loader.hide() loader.hide()
} }
async function deleteFolder(path: string) { async function deleteFolder(path: string) {
loader.show() loader.show()
await api.delete(constructUrl(path, false)) await api.delete<(typeof file.value)[string]>(
`${import.meta.env.VITE_API_ENDPOINT}storage/folder`,
{ data: { path: path.split('/').filter(Boolean) } },
)
loader.hide() loader.hide()
} }
type FileMetadata = { type FileMetadata = {
title?: string title?: string
description?: string description?: string
keyword?: string[]
category?: string[] category?: string[]
keyword?: string[]
} }
async function createFile( async function createFile(
file: File, file: File,
data: FileMetadata, data: FileMetadata,
path: string = currentInfo.path, path: string = currentInfo.path,
) { ) {
if (path.split('/').filter(Boolean).length < 3) return // the system only allow file to live in level 3 and 4 const arr = path.split('/').filter(Boolean)
if (arr.length < 3) return // the system only allow file to live in level 3 and 4
loader.show() loader.show()
const res = await api.post(constructUrl(path, false) + '/file', { const res = await api.post(
file: file.name, `${import.meta.env.VITE_API_ENDPOINT}storage/file`,
...data, {
}) path: arr,
if (res && res.status === 201 && res.data && res.data.upload) { file: file.name,
...data,
},
)
if (res && res.status === 200 && res.data && res.data.uploadUrl) {
await axios await axios
.put(res.data.upload, file, { .put(res.data.uploadUrl, file, {
headers: { 'Content-Type': file.type }, headers: { 'Content-Type': file.type },
onUploadProgress: (e) => console.log(e), onUploadProgress: (e) => console.log(e),
}) })
@ -416,13 +450,29 @@ const useStorage = defineStore('storageStore', () => {
if (arr.length < 4) return // the system only allow file to live in level 3 and 4 if (arr.length < 4) return // the system only allow file to live in level 3 and 4
loader.show() loader.show()
const res = await api.patch(
constructUrl(arr.slice(0, -1), false) + `/file/${arr[arr.length - 1]}`, const srcFile = arr.pop()
{ file: file?.name, ...data },
const res = await api.put(
`${import.meta.env.VITE_API_ENDPOINT}storage/file`,
{
...data,
from: {
file: srcFile,
path: arr,
},
to: file?.name
? {
file: file.name,
path: arr,
}
: undefined,
upload: !!file,
},
) )
if (res && res.status === 200 && res.data && res.data.upload) { if (res && res.status === 200 && res.data && res.data.uploadUrl) {
await axios await axios
.put(res.data.upload, file, { .put(res.data.uploadUrl, file, {
headers: { 'Content-Type': file?.type }, headers: { 'Content-Type': file?.type },
onUploadProgress: (e) => console.log(e), onUploadProgress: (e) => console.log(e),
}) })
@ -436,9 +486,10 @@ const useStorage = defineStore('storageStore', () => {
if (arr.length < 4) return // the system only allow file to live in level 3 and 4 if (arr.length < 4) return // the system only allow file to live in level 3 and 4
loader.show() loader.show()
await api.delete(
constructUrl(arr.slice(0, -1), false) + `/file/${arr[arr.length - 1]}`, await api.delete(`${import.meta.env.VITE_API_ENDPOINT}storage/file`, {
) data: { path: arr.slice(0, -1), file: arr[arr.length - 1] },
})
loader.hide() loader.hide()
} }
@ -461,6 +512,8 @@ const useStorage = defineStore('storageStore', () => {
createFile, createFile,
updateFile, updateFile,
deleteFile, deleteFile,
constructUrl,
consistantPath,
} }
}) })