hrms-edm/Services/client/src/stores/storage.ts

271 lines
7.2 KiB
TypeScript
Raw Normal View History

2023-12-10 09:27:26 +07:00
import { computed, reactive, ref } from 'vue'
import { defineStore } from 'pinia'
import { io } from 'socket.io-client'
2023-12-10 09:27:26 +07:00
import api from '@/services/HttpService'
import { useLoader } from './loader'
2023-12-10 09:27:26 +07:00
function constructUrl(path: string | string[], append = true) {
const arr = Array.isArray(path) ? path : path.split('/').filter(Boolean)
const url =
import.meta.env.VITE_API_ENDPOINT +
arr.reduce<string>((a, v, i) => {
switch (String(i)) {
case '0':
return `cabinet/${v}`
case '1':
return `${a}/drawer/${v}`
case '2':
return `${a}/folder/${v}`
case '3':
return `${a}/subfolder/${v}`
default:
return a
}
}, '')
return append
? url + ['cabinet', '/drawer', '/folder', '/subfolder'][arr.length]
: url
}
const useStorage = defineStore('storageStore', () => {
const loader = useLoader()
const init = ref<boolean>(false)
const folder = ref<
2023-12-10 09:27:26 +07:00
Record<
string, // path that contains folders
{
pathname: string
name: string
}[]
>
>({})
const file = ref<
2023-12-10 09:27:26 +07:00
Record<
string, // path that contains files
{
pathname: string
path: string
fileName: string
fileSize: string
fileType: string
title: string
description: string
category: string[]
keyword: string[]
updatedAt: string
updatedBy: string
createdAt: string
createdBy: string
}[]
>
>({})
const tree = computed(() => {
type Structure = {
pathname: string
name: string
folder: Structure
file: (typeof file.value)[string]
2023-12-10 09:27:26 +07:00
}[]
let structure: Structure = []
// parse list of folder and list of file into tree
Object.entries(folder.value).forEach(([key, value]) => {
2023-12-10 09:27:26 +07:00
const arr = key.split('/').filter(Boolean)
// init outer tree
if (arr.length === 0) {
if (!init.value) init.value = true
2023-12-10 09:27:26 +07:00
structure = value.map((v) => ({
pathname: v.pathname,
name: v.name,
folder: [],
file: [],
}))
} else {
let current: Structure[number] | undefined
// traverse into tree
arr.forEach((v, i) => {
current =
i === 0
? structure.find((x) => x.name === v)
: current?.folder.find((x) => x.name === v)
})
// set data in tree (object is references to the same object)
if (current) {
current.folder = value.map((v) => ({
pathname: v.pathname,
name: v.name,
folder: [],
file: [],
}))
current.file = file.value[key] ?? []
2023-12-10 09:27:26 +07:00
}
}
})
return structure
})
const currentInfo = reactive<{
path: string
dept: number
}>({
path: '',
dept: 1,
2023-12-10 09:27:26 +07:00
})
if (!init.value) goto()
2023-12-10 09:27:26 +07:00
async function getStorage(path: string = '') {
const arr = path.split('/').filter(Boolean)
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))
if (res.status === 200 && res.data && Array.isArray(res.data))
folder.value[path] = res.data.sort((a, b) =>
2023-12-10 09:27:26 +07:00
a.pathname.localeCompare(b.pathname),
)
}
async function getStorageFile(path: string = '') {
const arr = path.split('/').filter(Boolean)
if (arr.length < 3) return // file in this system only lives in level 3 and 4
2023-12-10 09:27:26 +07:00
const res = await api.get<(typeof file.value)[string]>(
constructUrl(arr, false) + '/file',
2023-12-10 09:27:26 +07:00
)
if (res.status === 200 && res.data && Array.isArray(res.data))
file.value[path] = res.data.sort((a, b) =>
2023-12-10 09:27:26 +07:00
a.pathname.localeCompare(b.pathname),
)
}
async function goto(path: string = '', force = false) {
loader.show()
2023-12-10 09:27:26 +07:00
const arr = path.split('/').filter(Boolean)
// get all parent to the root structure
2023-12-10 09:27:26 +07:00
for (let i = 0; i < arr.length; i++) {
const current = arr.slice(0, i - arr.length).join('/') + '/'
if (!folder.value[current] || force) await getStorage(current)
2023-12-10 09:27:26 +07:00
}
// only get this path once, after that will get from socket.io-client instead
if (!folder.value[path] || force) await getStorage(path)
if (!file.value[path] || force) await getStorageFile(path)
2023-12-10 09:27:26 +07:00
currentInfo.path = path
currentInfo.dept = path.split('/').filter(Boolean).length
loader.hide()
2023-12-10 09:27:26 +07:00
}
async function gotoParent() {
const arr = currentInfo.path.split('/').filter(Boolean)
await goto([...arr.slice(0, -1), ''].join('/'))
}
// socket.io zone
const socket = io('http://localhost:25565')
2023-12-10 09:27:26 +07:00
socket.on('connect', () => console.info('Socket.io connected.'))
socket.on('disconnect', () => console.info('Socket.io disconnected.'))
socket.on('CreateFolder', (data: { pathname: string }) => {
const arr = data.pathname.split('/').filter(Boolean)
const path = [...arr.slice(0, -1), ''].join('/')
if (folder.value[path]) {
folder.value[path].push({
2023-12-10 09:27:26 +07:00
pathname: data.pathname,
name: arr[arr.length - 1],
})
folder.value[path].sort((a, b) => a.pathname.localeCompare(b.pathname))
}
})
// NOTE:
// 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.
socket.on('EditFolder', (data: { from: string; to: string }) => {
const src = data.from.split('/').filter(Boolean)
const dst = data.to.split('/').filter(Boolean)
const path = [...src.slice(0, -1), ''].join('/')
if (folder.value[path]) {
const val = folder.value[path].find((v) => v.pathname === data.from)
if (val) {
val.pathname = data.to
val.name = dst[dst.length - 1]
}
}
for (let key in folder.value) {
if (key.startsWith(data.from)) {
folder.value[key.replace(data.from, data.to)] = folder.value[key].map(
(v) => {
v.pathname = v.pathname.replace(data.from, data.to)
return v
},
)
delete folder.value[key]
}
2023-12-10 09:27:26 +07:00
}
})
socket.on('DeleteFolder', (data: { pathname: string }) => {
for (let key in folder.value) {
if (key.startsWith(data.pathname)) {
delete folder.value[key]
}
2023-12-10 09:27:26 +07:00
}
const arr = data.pathname.split('/').filter(Boolean)
const path = [...arr.slice(0, -1), ''].join('/')
if (folder.value[path]) {
folder.value[path] = folder.value[path].filter(
2023-12-10 09:27:26 +07:00
(v) => v.pathname !== data.pathname,
)
}
})
async function createFolder(name: string, path: string = currentInfo.path) {
loader.show()
await api.post(constructUrl(path, true), { name })
loader.hide()
}
async function editFolder(name: string, path: string) {
loader.show()
await api.put(constructUrl(path), { name })
loader.hide()
}
async function deleteFolder(path: string) {
loader.show()
await api.delete(constructUrl(path))
loader.hide()
}
2023-12-10 09:27:26 +07:00
return {
// information
currentInfo,
folder,
file,
2023-12-10 09:27:26 +07:00
tree,
// fetch
getStorage,
getStorageFile,
// traverse
goto,
gotoParent,
// operation
createFolder,
editFolder,
deleteFolder,
2023-12-10 09:27:26 +07:00
}
})
export default useStorage