Md Afiq Iskandar 5501c00c7c Enhance Process Builder with Script Task Configuration
- 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.
2025-07-07 16:45:00 +08:00

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>