EDMS/pages/dms/index.vue
2025-05-30 21:08:11 +08:00

226 lines
6.6 KiB
Vue

<script setup>
import { ref, computed, onMounted } from 'vue';
import { useDmsStore } from '~/stores/dms';
import DMSNavigation from '~/components/dms/navigation/DMSNavigation.vue';
import DMSExplorer from '~/components/dms/explorer/DMSExplorer.vue';
// Define page metadata
definePageMeta({
title: "Document Management System",
middleware: ["auth"],
requiresAuth: true,
breadcrumb: [
{
name: "DMS",
path: "/dms",
},
],
});
// Set up store
const dmsStore = useDmsStore();
// Local state
const showFileViewer = ref(false);
const currentDocument = ref(null);
const searchQuery = ref('');
const isSearching = ref(false);
const currentPath = ref('JKR Cawangan Kota Bharu, Kelantan');
const viewMode = ref('explorer'); // explorer, cabinets, list
const selectedItem = ref(null);
const activeTab = ref('all');
// File selection state
const selectedFiles = ref([]);
const isSelecting = ref(false);
// Toggle file selection
const toggleFileSelection = (file) => {
const index = selectedFiles.value.findIndex(f => f.id === file.id);
if (index === -1) {
selectedFiles.value.push(file);
} else {
selectedFiles.value.splice(index, 1);
}
};
// Clear selection
const clearSelection = () => {
selectedFiles.value = [];
isSelecting.value = false;
};
// Select all files
const selectAllFiles = () => {
selectedFiles.value = [...dmsStore.currentItems];
isSelecting.value = true;
};
// Check if a file is selected
const isFileSelected = (file) => {
return selectedFiles.value.some(f => f.id === file.id);
};
// Toggle view mode
const changeViewMode = (mode) => {
viewMode.value = mode;
};
// View a file
const viewFile = (file) => {
if (isSelecting.value) {
toggleFileSelection(file);
return;
}
currentDocument.value = file;
showFileViewer.value = true;
};
// Navigate to a location
const navigateTo = (path) => {
currentPath.value = path;
// In a real app, we would fetch the contents of this location
clearSelection();
};
// Search functionality
const handleSearch = async () => {
if (!searchQuery.value.trim()) return;
isSearching.value = true;
await dmsStore.searchDocuments(searchQuery.value);
isSearching.value = false;
};
// Clear search
const clearSearch = () => {
searchQuery.value = '';
dmsStore.clearSearch();
};
// Format file size
const formatFileSize = (size) => {
if (!size) return '0 B';
if (typeof size === 'string') {
// If already formatted (like "4MB"), return as is
if (size.endsWith('B')) return size;
// Try to parse the size if it's a number in string form
const parsed = parseFloat(size);
if (isNaN(parsed)) return size;
size = parsed;
}
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
let i = 0;
while (size >= 1024 && i < units.length - 1) {
size /= 1024;
i++;
}
return `${size.toFixed(2)} ${units[i]}`;
};
// Document category tabs
const documentTabs = [
{ id: 'all', label: 'All Documents', icon: 'folder' },
{ id: 'public', label: 'Public', icon: 'unlock' },
{ id: 'private', label: 'Private', icon: 'lock' },
{ id: 'personal', label: 'Personal', icon: 'user' }
];
// Handle events from explorer
const handleItemSelected = (item) => {
selectedItem.value = item;
};
const handleViewModeChanged = (mode) => {
console.log('View mode changed to:', mode);
};
const handlePathChanged = (path) => {
currentPath.value = path;
};
// Get SVG icon
const getSvgIcon = (iconType, size = 16) => {
const icons = {
folder: `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>`,
unlock: `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 9.9-1"></path></svg>`,
lock: `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>`,
user: `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>`
};
return icons[iconType] || icons.folder;
};
// Lifecycle hooks
onMounted(() => {
// Any initialization logic
});
</script>
<template>
<div class="dms-page">
<LayoutsBreadcrumb />
<rs-card class="h-full">
<template #body>
<div class="dms-layout h-full flex flex-col">
<!-- Document Category Tabs -->
<div class="tabs-header border-b border-gray-200 dark:border-gray-700 p-4 bg-white dark:bg-gray-800">
<div class="flex items-center space-x-1">
<button
v-for="tab in documentTabs"
:key="tab.id"
@click="activeTab = tab.id"
class="flex items-center space-x-2 px-4 py-2 rounded-lg text-sm font-medium transition-colors"
:class="activeTab === tab.id
? 'bg-blue-100 text-blue-700 dark:bg-blue-900/20 dark:text-blue-300'
: 'text-gray-600 hover:text-gray-900 hover:bg-gray-100 dark:text-gray-400 dark:hover:text-gray-200 dark:hover:bg-gray-700'"
>
<span v-html="getSvgIcon(tab.icon, 16)"></span>
<span>{{ tab.label }}</span>
</button>
</div>
</div>
<!-- Explorer Component -->
<div class="explorer-container flex-1 overflow-hidden">
<DMSExplorer
:initial-path="'/'"
:view-mode="'list'"
:active-document-tab="activeTab"
@item-selected="handleItemSelected"
@view-mode-changed="handleViewModeChanged"
@path-changed="handlePathChanged"
/>
</div>
</div>
</template>
</rs-card>
</div>
</template>
<style scoped>
.dms-page {
height: calc(100vh - 64px);
}
.dms-layout {
height: 100%;
}
.explorer-container {
min-height: 0;
}
/* Ensure smooth transitions */
.tabs-header button {
transition: all 0.2s ease;
}
.tabs-header button:hover {
transform: translateY(-1px);
}
</style>