Merge branch 'net' into development
This commit is contained in:
commit
e65fb9f5d9
2 changed files with 139 additions and 44 deletions
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue