- Introduced a new ScriptNodeConfiguration component for configuring JavaScript tasks within the process builder. - Added ScriptNodeConfigurationModal for user-friendly script task setup, including input and output variable management. - Updated process management logic to handle script variables directly within the process store, improving variable management and accessibility. - Enhanced existing components to support the new script task feature, ensuring seamless integration with the process flow. - Improved overall user experience with intuitive UI elements and clear documentation for the new functionality.
473 lines
17 KiB
Vue
473 lines
17 KiB
Vue
<script setup>
|
|
import { ref, computed, onMounted } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import { useProcessBuilderStore } from '~/stores/processBuilder'
|
|
|
|
definePageMeta({
|
|
title: "Dashboard - Corrad BPM",
|
|
middleware: ["auth"],
|
|
requiresAuth: true,
|
|
});
|
|
|
|
const router = useRouter()
|
|
const processStore = useProcessBuilderStore()
|
|
|
|
// Dashboard stats
|
|
const stats = ref({
|
|
activeProcesses: 0,
|
|
totalForms: 0,
|
|
pendingTasks: 0,
|
|
completedInstances: 0
|
|
})
|
|
|
|
// Recent activity data
|
|
const recentProcesses = ref([])
|
|
const recentTasks = ref([])
|
|
|
|
// System features data
|
|
const systemFeatures = [
|
|
{
|
|
id: 'process-builder',
|
|
title: 'Process Builder',
|
|
description: 'Design business workflows with drag-and-drop visual editor',
|
|
icon: 'material-symbols:account-tree',
|
|
color: 'bg-blue-500',
|
|
colorLight: 'bg-blue-100',
|
|
textColor: 'text-blue-600',
|
|
route: '/process-builder',
|
|
features: ['Visual Workflow Designer', 'BPMN 2.0 Support', 'Real-time Collaboration']
|
|
},
|
|
{
|
|
id: 'form-builder',
|
|
title: 'Form Builder',
|
|
description: 'Create dynamic forms with advanced components and logic',
|
|
icon: 'material-symbols:description',
|
|
color: 'bg-purple-500',
|
|
colorLight: 'bg-purple-100',
|
|
textColor: 'text-purple-600',
|
|
route: '/form-builder',
|
|
features: ['Drag & Drop Form Builder', 'Conditional Logic', 'FormKit Integration']
|
|
},
|
|
{
|
|
id: 'execution-engine',
|
|
title: 'Execution Engine',
|
|
description: 'Run and manage process instances with monitoring',
|
|
icon: 'material-symbols:play-circle',
|
|
color: 'bg-green-500',
|
|
colorLight: 'bg-green-100',
|
|
textColor: 'text-green-600',
|
|
route: '/execution',
|
|
features: ['Process Execution', 'Task Management', 'Instance Monitoring']
|
|
},
|
|
{
|
|
id: 'api-integrations',
|
|
title: 'API Integrations',
|
|
description: 'Connect with external systems and services',
|
|
icon: 'material-symbols:api',
|
|
color: 'bg-orange-500',
|
|
colorLight: 'bg-orange-100',
|
|
textColor: 'text-orange-600',
|
|
route: '/devtool/api-editor',
|
|
features: ['REST API Calls', 'Webhook Support', 'Data Transformation']
|
|
}
|
|
]
|
|
|
|
// Quick actions
|
|
const quickActions = [
|
|
{
|
|
title: 'Create New Process',
|
|
description: 'Start building a new business process',
|
|
icon: 'material-symbols:add-circle',
|
|
color: 'bg-emerald-500',
|
|
action: () => router.push('/process-builder')
|
|
},
|
|
{
|
|
title: 'Design Form',
|
|
description: 'Build interactive forms',
|
|
icon: 'material-symbols:edit-document',
|
|
color: 'bg-indigo-500',
|
|
action: () => router.push('/form-builder')
|
|
},
|
|
{
|
|
title: 'View Inbox',
|
|
description: 'Check pending tasks',
|
|
icon: 'material-symbols:inbox',
|
|
color: 'bg-rose-500',
|
|
action: () => router.push('/execution/inbox')
|
|
},
|
|
{
|
|
title: 'Manage Processes',
|
|
description: 'View all processes',
|
|
icon: 'material-symbols:folder-managed',
|
|
color: 'bg-amber-500',
|
|
action: () => router.push('/process-builder/manage')
|
|
}
|
|
]
|
|
|
|
// Development roadmap
|
|
const developmentRoadmap = [
|
|
{
|
|
phase: 'Phase 1 - Foundation',
|
|
status: 'completed',
|
|
items: [
|
|
'Process Builder with Visual Designer',
|
|
'Form Builder with Dynamic Components',
|
|
'Basic Process Execution Engine',
|
|
'User Authentication & Authorization'
|
|
]
|
|
},
|
|
{
|
|
phase: 'Phase 2 - Integration',
|
|
status: 'in-progress',
|
|
items: [
|
|
'API Node Integration',
|
|
'Email & SMS Notifications',
|
|
'Business Rules Engine',
|
|
'Process Templates & Versioning'
|
|
]
|
|
},
|
|
{
|
|
phase: 'Phase 3 - Advanced Features',
|
|
status: 'planned',
|
|
items: [
|
|
'Advanced Analytics & Reporting',
|
|
'Process Mining & Optimization',
|
|
'Mobile App Support',
|
|
'Enterprise Connectors'
|
|
]
|
|
}
|
|
]
|
|
|
|
// Load dashboard data
|
|
const loadDashboardData = async () => {
|
|
try {
|
|
// Load recent processes
|
|
await processStore.fetchProcesses({ limit: 5, sortBy: 'processModifiedDate', sortOrder: 'desc' })
|
|
recentProcesses.value = processStore.processes.slice(0, 5)
|
|
|
|
// Update stats
|
|
stats.value = {
|
|
activeProcesses: processStore.processes.filter(p => p.status === 'published').length,
|
|
totalForms: processStore.processes.length,
|
|
pendingTasks: Math.floor(Math.random() * 25) + 5, // Mock data
|
|
completedInstances: Math.floor(Math.random() * 150) + 50 // Mock data
|
|
}
|
|
|
|
// Mock recent tasks
|
|
recentTasks.value = [
|
|
{ id: 1, title: 'Review Profile Registration', process: 'Pendaftaran Profil', assignee: 'You', dueDate: '2024-01-15' },
|
|
{ id: 2, title: 'Approve Leave Request', process: 'Leave Management', assignee: 'HR Team', dueDate: '2024-01-16' },
|
|
{ id: 3, title: 'Verify Documents', process: 'Document Verification', assignee: 'Admin', dueDate: '2024-01-17' }
|
|
]
|
|
} catch (error) {
|
|
console.error('Error loading dashboard data:', error)
|
|
}
|
|
}
|
|
|
|
// Navigation helpers
|
|
const navigateToFeature = (route) => {
|
|
router.push(route)
|
|
}
|
|
|
|
const getStatusColor = (status) => {
|
|
switch (status) {
|
|
case 'completed': return 'text-green-600 bg-green-100'
|
|
case 'in-progress': return 'text-blue-600 bg-blue-100'
|
|
case 'planned': return 'text-gray-600 bg-gray-100'
|
|
default: return 'text-gray-600 bg-gray-100'
|
|
}
|
|
}
|
|
|
|
const formatDate = (dateString) => {
|
|
return new Date(dateString).toLocaleDateString('en-US', {
|
|
month: 'short',
|
|
day: 'numeric',
|
|
year: 'numeric'
|
|
})
|
|
}
|
|
|
|
onMounted(() => {
|
|
loadDashboardData()
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="space-y-6">
|
|
<LayoutsBreadcrumb />
|
|
|
|
<!-- Welcome Header -->
|
|
<div class="bg-gradient-to-r from-blue-600 to-purple-600 rounded-xl p-8 text-white">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h1 class="text-3xl font-bold mb-2">Welcome to Corrad BPM</h1>
|
|
<p class="text-blue-100 text-lg">Business Process Management & Workflow Automation Platform</p>
|
|
</div>
|
|
<div class="hidden md:block">
|
|
<Icon name="material-symbols:float-landscape" class="w-20 h-20 text-blue-200" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- System Statistics -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6">
|
|
<rs-card class="hover:shadow-lg transition-shadow">
|
|
<div class="p-6 flex items-center">
|
|
<div class="p-4 bg-blue-100 rounded-xl mr-4">
|
|
<Icon name="material-symbols:account-tree" class="w-8 h-8 text-blue-600" />
|
|
</div>
|
|
<div>
|
|
<div class="text-2xl font-bold text-gray-900">{{ stats.activeProcesses }}</div>
|
|
<div class="text-sm text-gray-500">Active Processes</div>
|
|
</div>
|
|
</div>
|
|
</rs-card>
|
|
|
|
<rs-card class="hover:shadow-lg transition-shadow">
|
|
<div class="p-6 flex items-center">
|
|
<div class="p-4 bg-purple-100 rounded-xl mr-4">
|
|
<Icon name="material-symbols:description" class="w-8 h-8 text-purple-600" />
|
|
</div>
|
|
<div>
|
|
<div class="text-2xl font-bold text-gray-900">{{ stats.totalForms }}</div>
|
|
<div class="text-sm text-gray-500">Total Forms</div>
|
|
</div>
|
|
</div>
|
|
</rs-card>
|
|
|
|
<rs-card class="hover:shadow-lg transition-shadow">
|
|
<div class="p-6 flex items-center">
|
|
<div class="p-4 bg-orange-100 rounded-xl mr-4">
|
|
<Icon name="material-symbols:pending-actions" class="w-8 h-8 text-orange-600" />
|
|
</div>
|
|
<div>
|
|
<div class="text-2xl font-bold text-gray-900">{{ stats.pendingTasks }}</div>
|
|
<div class="text-sm text-gray-500">Pending Tasks</div>
|
|
</div>
|
|
</div>
|
|
</rs-card>
|
|
|
|
<rs-card class="hover:shadow-lg transition-shadow">
|
|
<div class="p-6 flex items-center">
|
|
<div class="p-4 bg-green-100 rounded-xl mr-4">
|
|
<Icon name="material-symbols:task-alt" class="w-8 h-8 text-green-600" />
|
|
</div>
|
|
<div>
|
|
<div class="text-2xl font-bold text-gray-900">{{ stats.completedInstances }}</div>
|
|
<div class="text-sm text-gray-500">Completed Instances</div>
|
|
</div>
|
|
</div>
|
|
</rs-card>
|
|
</div>
|
|
|
|
<!-- Quick Actions -->
|
|
<rs-card>
|
|
<template #header>
|
|
<div class="flex items-center">
|
|
<Icon name="material-symbols:flash-on" class="w-5 h-5 mr-2 text-yellow-500" />
|
|
Quick Actions
|
|
</div>
|
|
</template>
|
|
<template #body>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-4">
|
|
<div
|
|
v-for="action in quickActions"
|
|
:key="action.title"
|
|
@click="action.action"
|
|
class="p-4 border border-gray-200 rounded-lg hover:border-gray-300 hover:shadow-md transition-all cursor-pointer group"
|
|
>
|
|
<div class="flex items-center mb-3">
|
|
<div :class="[action.color, 'p-2 rounded-lg mr-3 group-hover:scale-110 transition-transform']">
|
|
<Icon :name="action.icon" class="w-5 h-5 text-white" />
|
|
</div>
|
|
<h3 class="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors">{{ action.title }}</h3>
|
|
</div>
|
|
<p class="text-sm text-gray-600">{{ action.description }}</p>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</rs-card>
|
|
|
|
<div class="grid grid-cols-1 xl:grid-cols-2 gap-6">
|
|
<!-- System Features -->
|
|
<rs-card class="xl:col-span-1">
|
|
<template #header>
|
|
<div class="flex items-center">
|
|
<Icon name="material-symbols:featured-play-list" class="w-5 h-5 mr-2 text-blue-500" />
|
|
System Features
|
|
</div>
|
|
</template>
|
|
<template #body>
|
|
<div class="space-y-6">
|
|
<div
|
|
v-for="feature in systemFeatures"
|
|
:key="feature.id"
|
|
class="border border-gray-200 rounded-lg p-4 hover:border-gray-300 hover:shadow-sm transition-all cursor-pointer group"
|
|
@click="navigateToFeature(feature.route)"
|
|
>
|
|
<div class="flex items-start">
|
|
<div :class="[feature.colorLight, 'p-3 rounded-lg mr-4 group-hover:scale-105 transition-transform']">
|
|
<Icon :name="feature.icon" :class="[feature.textColor, 'w-6 h-6']" />
|
|
</div>
|
|
<div class="flex-1">
|
|
<h3 class="font-semibold text-gray-900 mb-1 group-hover:text-blue-600 transition-colors">{{ feature.title }}</h3>
|
|
<p class="text-sm text-gray-600 mb-3">{{ feature.description }}</p>
|
|
<div class="flex flex-wrap gap-2">
|
|
<span
|
|
v-for="item in feature.features.slice(0, 2)"
|
|
:key="item"
|
|
class="px-2 py-1 bg-gray-100 text-gray-600 text-xs rounded-full"
|
|
>
|
|
{{ item }}
|
|
</span>
|
|
<span
|
|
v-if="feature.features.length > 2"
|
|
class="px-2 py-1 bg-gray-100 text-gray-600 text-xs rounded-full"
|
|
>
|
|
+{{ feature.features.length - 2 }} more
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<Icon name="material-symbols:arrow-forward" class="w-5 h-5 text-gray-400 group-hover:text-blue-500 transition-colors" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</rs-card>
|
|
|
|
<!-- Recent Activity -->
|
|
<rs-card class="xl:col-span-1">
|
|
<template #header>
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex items-center">
|
|
<Icon name="material-symbols:history" class="w-5 h-5 mr-2 text-gray-500" />
|
|
Recent Activity
|
|
</div>
|
|
<RsButton variant="secondary" size="sm" @click="router.push('/execution/history')">
|
|
View All
|
|
</RsButton>
|
|
</div>
|
|
</template>
|
|
<template #body>
|
|
<div class="space-y-4">
|
|
<!-- Recent Processes -->
|
|
<div>
|
|
<h4 class="font-medium text-gray-900 mb-3">Recent Processes</h4>
|
|
<div class="space-y-3">
|
|
<div
|
|
v-for="process in recentProcesses.slice(0, 3)"
|
|
:key="process.id"
|
|
class="flex items-center justify-between p-3 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors cursor-pointer"
|
|
@click="router.push(`/process-builder?id=${process.id}`)"
|
|
>
|
|
<div class="flex items-center">
|
|
<div class="w-2 h-2 bg-blue-500 rounded-full mr-3"></div>
|
|
<div>
|
|
<div class="font-medium text-sm text-gray-900">{{ process.name }}</div>
|
|
<div class="text-xs text-gray-500">{{ formatDate(process.updatedAt) }}</div>
|
|
</div>
|
|
</div>
|
|
<RsBadge :variant="process.status === 'published' ? 'success' : 'warning'" size="sm">
|
|
{{ process.status }}
|
|
</RsBadge>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Tasks -->
|
|
<div>
|
|
<h4 class="font-medium text-gray-900 mb-3">Pending Tasks</h4>
|
|
<div class="space-y-3">
|
|
<div
|
|
v-for="task in recentTasks"
|
|
:key="task.id"
|
|
class="flex items-center justify-between p-3 bg-amber-50 rounded-lg hover:bg-amber-100 transition-colors cursor-pointer"
|
|
@click="router.push('/execution/inbox')"
|
|
>
|
|
<div class="flex items-center">
|
|
<div class="w-2 h-2 bg-amber-500 rounded-full mr-3"></div>
|
|
<div>
|
|
<div class="font-medium text-sm text-gray-900">{{ task.title }}</div>
|
|
<div class="text-xs text-gray-500">{{ task.process }} • Due {{ task.dueDate }}</div>
|
|
</div>
|
|
</div>
|
|
<Icon name="material-symbols:keyboard-arrow-right" class="w-5 h-5 text-gray-400" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</rs-card>
|
|
</div>
|
|
|
|
<!-- Development Roadmap -->
|
|
<rs-card>
|
|
<template #header>
|
|
<div class="flex items-center">
|
|
<Icon name="material-symbols:road" class="w-5 h-5 mr-2 text-purple-500" />
|
|
Development Roadmap & System Guide
|
|
</div>
|
|
</template>
|
|
<template #body>
|
|
<div class="space-y-6">
|
|
<div class="bg-blue-50 border border-blue-200 rounded-lg p-4">
|
|
<h3 class="font-semibold text-blue-900 mb-2">🚀 Getting Started with Corrad BPM</h3>
|
|
<p class="text-blue-800 text-sm mb-3">
|
|
Follow these steps to start developing business processes in the system:
|
|
</p>
|
|
<ol class="list-decimal list-inside space-y-1 text-sm text-blue-800">
|
|
<li><strong>Design Forms:</strong> Use Form Builder to create data collection forms</li>
|
|
<li><strong>Create Processes:</strong> Use Process Builder to design workflow logic</li>
|
|
<li><strong>Configure Integrations:</strong> Set up API calls and business rules</li>
|
|
<li><strong>Test & Deploy:</strong> Test process execution and publish to production</li>
|
|
</ol>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
<div
|
|
v-for="phase in developmentRoadmap"
|
|
:key="phase.phase"
|
|
class="border border-gray-200 rounded-lg p-4"
|
|
>
|
|
<div class="flex items-center justify-between mb-3">
|
|
<h4 class="font-semibold text-gray-900">{{ phase.phase }}</h4>
|
|
<RsBadge :class="getStatusColor(phase.status)" size="sm">
|
|
{{ phase.status.replace('-', ' ') }}
|
|
</RsBadge>
|
|
</div>
|
|
<ul class="space-y-2">
|
|
<li
|
|
v-for="item in phase.items"
|
|
:key="item"
|
|
class="flex items-start text-sm text-gray-600"
|
|
>
|
|
<Icon
|
|
:name="phase.status === 'completed' ? 'material-symbols:check-circle' :
|
|
phase.status === 'in-progress' ? 'material-symbols:radio-button-partial' :
|
|
'material-symbols:radio-button-unchecked'"
|
|
:class="phase.status === 'completed' ? 'text-green-500' :
|
|
phase.status === 'in-progress' ? 'text-blue-500' :
|
|
'text-gray-400'"
|
|
class="w-4 h-4 mr-2 mt-0.5 flex-shrink-0"
|
|
/>
|
|
{{ item }}
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</rs-card>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
/* Custom hover effects and transitions */
|
|
.group:hover .group-hover\:scale-105 {
|
|
transform: scale(1.05);
|
|
}
|
|
|
|
.group:hover .group-hover\:scale-110 {
|
|
transform: scale(1.1);
|
|
}
|
|
</style>
|