Enhance Documentation and Navigation for Process Execution Module

- Added new sections in the README and PROJECT_OVERVIEW to include user and technical guides for the Process Execution interface.
- Updated navigation structure to incorporate the Process Execution module, detailing features such as the Execution Dashboard, Task Inbox, and Case History.
- Improved overall documentation clarity and organization to assist users in understanding the new process execution functionalities.
This commit is contained in:
Md Afiq Iskandar 2025-05-21 13:36:43 +08:00
parent 2136aecdbd
commit 0a4d41df06
12 changed files with 1888 additions and 0 deletions

135
components/TaskForm.vue Normal file
View File

@ -0,0 +1,135 @@
<template>
<div class="bg-white rounded-lg shadow">
<!-- Task Header -->
<div class="p-6 border-b border-gray-200">
<div class="flex flex-wrap justify-between items-start">
<div>
<h2 class="text-xl font-bold text-gray-800">{{ task.name }}</h2>
<div class="mt-1 text-sm text-gray-600">
<span>Process: {{ task.process }}</span>
<span class="mx-2"></span>
<span>Case #{{ task.caseId }}</span>
</div>
</div>
<div class="flex items-center mt-2 sm:mt-0">
<span
:class="[
'px-2 py-1 text-xs font-medium rounded-full mr-3',
task.status === 'pending' ? 'bg-yellow-100 text-yellow-800' :
task.status === 'overdue' ? 'bg-red-100 text-red-800' :
'bg-green-100 text-green-800'
]"
>
{{ task.status.charAt(0).toUpperCase() + task.status.slice(1) }}
</span>
<span class="text-sm text-gray-600">
Due: {{ task.dueDate }}
</span>
</div>
</div>
</div>
<!-- Task Instructions -->
<div class="p-6 border-b border-gray-200 bg-gray-50">
<h3 class="text-sm font-medium text-gray-700 mb-2">Instructions</h3>
<div class="text-gray-600">
{{ task.instructions }}
</div>
</div>
<!-- Form -->
<div class="p-6">
<FormKit
type="form"
:actions="false"
v-if="formSchema"
:value="formData"
@submit="submitForm"
>
<!-- Rendered dynamically based on formSchema -->
<FormKitSchema :schema="formSchema" />
</FormKit>
<!-- Placeholder for when we don't have actual form data -->
<div v-else class="space-y-4">
<div class="space-y-2">
<label class="block text-sm font-medium text-gray-700">Purchase Order Number</label>
<input type="text" value="PO-2024-0123" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm" />
</div>
<div class="space-y-2">
<label class="block text-sm font-medium text-gray-700">Department</label>
<select class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm">
<option>IT Department</option>
<option>Marketing</option>
<option>Sales</option>
<option>Finance</option>
</select>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium text-gray-700">Amount</label>
<input type="text" value="$5,250.00" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm" />
</div>
<div class="space-y-2">
<label class="block text-sm font-medium text-gray-700">Vendor</label>
<input type="text" value="Acme Computing Supplies" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm" />
</div>
<div class="space-y-2">
<label class="block text-sm font-medium text-gray-700">Request Reason</label>
<textarea rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm">
Purchase of new developer workstations for the expanding engineering team.
</textarea>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium text-gray-700">Review Comments</label>
<textarea rows="3" placeholder="Enter your review comments here..." class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm"></textarea>
</div>
</div>
</div>
<!-- Action Buttons -->
<div class="p-6 border-t border-gray-200 flex justify-end space-x-4">
<button class="px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50">
Save Draft
</button>
<button class="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-red-600 hover:bg-red-700">
Reject
</button>
<button class="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700">
Approve
</button>
</div>
</div>
</template>
<script setup>
const props = defineProps({
task: {
type: Object,
default: () => ({
id: 'task-123',
name: 'Complete Purchase Order Review',
process: 'Purchase Order Approval',
caseId: 'PO-2024-0123',
status: 'pending',
dueDate: 'Apr 30, 2024',
instructions: 'Please review the purchase order details and either approve or reject the request. If rejecting, please provide a reason in the comments section.'
})
},
formSchema: {
type: Array,
default: null
}
});
const formData = ref({});
const submitForm = (data) => {
console.log('Form submitted:', data);
// Here would go the code to submit the form data to the backend
};
</script>

View File

@ -20,6 +20,10 @@ The documentation is organized into the following sections:
- [User Guide](./form-builder/USER_GUIDE.md) - How to use the Form Builder - [User Guide](./form-builder/USER_GUIDE.md) - How to use the Form Builder
- [Technical Guide](./form-builder/TECHNICAL_GUIDE.md) - Technical details of the Form Builder implementation - [Technical Guide](./form-builder/TECHNICAL_GUIDE.md) - Technical details of the Form Builder implementation
### Process Execution
- [User Guide](./process-execution/USER_GUIDE.md) - How to use the Process Execution interface
- [Technical Guide](./process-execution/TECHNICAL_GUIDE.md) - Technical details of the Process Execution implementation
## Getting Started ## Getting Started
New to the project? We recommend reading the documentation in this order: New to the project? We recommend reading the documentation in this order:

View File

@ -68,6 +68,27 @@ The Form Builder complements the Process Builder, enabling users to create forms
- Form versioning and management - Form versioning and management
- Integration with processes - Integration with processes
### Process Execution
The Process Execution module provides the end-user interface for interacting with deployed workflow processes. Key features include:
- Execution Dashboard for process overview
- Task statistics and metrics
- Recent tasks and processes
- Task Inbox for managing assigned tasks
- Task filtering and search
- Status indicators and due dates
- New Case interface for initiating processes
- Process catalog with descriptions
- Categorized process listing
- Case History for tracking process instances
- Historical record of completed processes
- Timeline visualization of process steps
- Task Detail interface for completing tasks
- Dynamic form rendering
- Case context and variables
- Process timeline visualization
## User Flows ## User Flows
### Process Design and Execution ### Process Design and Execution
@ -92,6 +113,15 @@ The Form Builder complements the Process Builder, enabling users to create forms
6. When a form task is encountered in a process, the assigned user sees the form 6. When a form task is encountered in a process, the assigned user sees the form
7. Form submissions store data in the process variables 7. Form submissions store data in the process variables
### Process Participation
1. User logs into the system and views their task inbox
2. User opens and completes assigned tasks
3. User submits task forms with required data
4. Process advances based on task completion
5. User can view process history and status
6. User can initiate new process instances
## Data Flow ## Data Flow
1. Process execution begins at a start event 1. Process execution begins at a start event

View File

@ -0,0 +1,278 @@
# Process Execution - Technical Guide
## Introduction
The Process Execution module forms the user-facing interface of the workflow system, enabling end-users to interact with processes designed in the Process Builder. This document outlines the technical implementation of the Process Execution module, aimed at developers who need to understand, maintain, or extend the system.
## Architecture Overview
The Process Execution module is built with the following technologies:
- **Frontend**: Vue 3 components with Nuxt 3 for routing and SSR
- **State Management**: Pinia stores for managing process and task data
- **UI Components**: Rose UI components (rs-prefixed) for consistent styling
- **Form Handling**: FormKit for dynamic form rendering and validation
- **Data Fetching**: Fetch composables with caching for API interactions
```
┌─────────────────────────────────────────────────────────────┐
│ Process Execution Module │
├─────────────┬─────────────┬─────────────┬──────────────────┤
│ Dashboard │ New Case │ Task Inbox │ Case History │
├─────────────┴─────────────┴─────────────┴──────────────────┤
│ Task Detail & Form Rendering Engine │
├─────────────────────────────────────────────────────────────┤
│ API Layer │
└─────────────────────────────────────────────────────────────┘
```
## Module Components
### Pages
The module consists of five main pages:
1. **Execution Dashboard** (`pages/execution/index.vue`)
- Aggregates process and task data
- Displays statistics and recent items
- Provides navigation to other execution pages
2. **New Case Page** (`pages/execution/new-case.vue`)
- Lists available processes that can be initiated
- Includes filtering and search functionality
- Handles process instantiation
3. **Task Inbox** (`pages/execution/inbox.vue`)
- Lists tasks assigned to the current user
- Provides advanced filtering options
- Handles task status updates
4. **Case History** (`pages/execution/history.vue`)
- Lists process instances and their statuses
- Provides filtering by multiple criteria
- Offers detailed case information access
5. **Task Detail** (`pages/execution/task/[id].vue`)
- Renders task-specific forms
- Displays case variables and process timeline
- Handles task completion actions
### Components
Key components used throughout the module:
1. **TaskForm.vue**
- Renders dynamic task forms based on task definition
- Handles validation and submission
- Uses FormKit for form element rendering
### Data Models
The module interacts with several data models:
1. **Process Instance**
```typescript
interface ProcessInstance {
id: string;
processDefinitionId: string;
name: string;
status: 'ACTIVE' | 'COMPLETED' | 'CANCELLED' | 'ERROR';
startDate: string;
endDate?: string;
variables: Record<string, any>;
tasks: Task[];
}
```
2. **Task**
```typescript
interface Task {
id: string;
name: string;
processInstanceId: string;
status: 'PENDING' | 'COMPLETED' | 'OVERDUE';
assignee: string;
dueDate?: string;
formKey?: string;
formData?: Record<string, any>;
}
```
## API Endpoints
The module interacts with the following API endpoints:
### Processes
- `GET /api/processes` - Retrieve available process definitions
- `POST /api/processes/{processId}/start` - Start a new process instance
- `GET /api/processes/instances` - Retrieve process instances
- `GET /api/processes/instances/{instanceId}` - Get a specific process instance
### Tasks
- `GET /api/tasks` - Retrieve tasks assigned to the current user
- `GET /api/tasks/{taskId}` - Get a specific task
- `POST /api/tasks/{taskId}/complete` - Complete a task with form data
- `POST /api/tasks/{taskId}/claim` - Claim a task assignment
- `POST /api/tasks/{taskId}/unclaim` - Release a task assignment
## Authentication and Authorization
The module relies on the application's authentication system with specific considerations:
- All execution pages require authentication (using the `auth` middleware)
- Task accessibility is determined by task assignment
- Process start permissions are controlled by user roles
- Case history visibility respects process instance permissions
## State Management
Process Execution uses Pinia stores to manage state:
```typescript
// Store for task management
export const useTaskStore = defineStore('task', {
state: () => ({
tasks: [],
currentTask: null,
loading: false,
error: null
}),
actions: {
async fetchTasks() {
// Implementation
},
async fetchTask(taskId) {
// Implementation
},
async completeTask(taskId, formData) {
// Implementation
}
}
});
// Store for process management
export const useProcessStore = defineStore('process', {
state: () => ({
processDefinitions: [],
processInstances: [],
currentInstance: null,
loading: false,
error: null
}),
actions: {
async fetchProcessDefinitions() {
// Implementation
},
async startProcess(processId, initialData) {
// Implementation
},
async fetchProcessInstances() {
// Implementation
}
}
});
```
## Form Rendering
Process Execution dynamically renders forms based on form definitions:
1. Forms are retrieved from the Form Builder's repository
2. FormKit schema is generated from the form definition
3. The schema is rendered using FormKit components
4. Validation rules are applied based on form configuration
5. Submission data is processed and sent to the API
```javascript
// Example of form rendering
function renderTaskForm(formDefinition) {
const schema = convertToFormKitSchema(formDefinition);
return createForm({
schema,
onSubmit: async (formData) => {
await completeTask(currentTaskId.value, formData);
}
});
}
```
## Status Tracking and Visualization
Process status visualization is implemented using:
1. **Status Badges**
- Color-coded status indicators (success, warning, danger)
- Text labels for clear status identification
2. **Process Timeline**
- Sequential visualization of process steps
- Status indicators for each step
- Current position indicator in the flow
## Performance Considerations
1. **Data Caching**
- Task and process data is cached to minimize API calls
- Caching invalidated on relevant state changes
2. **Pagination**
- Task lists and process history implement pagination
- Configurable page sizes to optimize data loading
3. **Lazy Loading**
- Task details and forms are lazy-loaded
- Expandable sections to reduce initial load time
## Error Handling
1. **API Error Handling**
- Centralized error handling for API responses
- User-friendly error messages for common issues
- Detailed logging for debugging
2. **Form Validation**
- Client-side validation to reduce server load
- Consistent error presentation for form fields
- Submission validation to prevent data loss
## Future Improvements
Planned technical enhancements for the Process Execution module:
1. **Real-time Updates**
- WebSocket integration for task list updates
- Notifications for new task assignments
2. **Offline Support**
- Task caching for offline access
- Offline form submission queuing
3. **Performance Optimization**
- Virtual scrolling for large task lists
- Optimized form rendering for complex forms
4. **Integration Enhancements**
- Enhanced document handling capabilities
- External system integrations for task actions
## Development Guidelines
When extending the Process Execution module:
1. **Component Reuse**
- Utilize existing Rose UI components
- Follow established patterns for new components
2. **State Management**
- Use appropriate stores for data management
- Maintain clear actions and mutations
3. **Form Handling**
- Follow FormKit patterns for form implementation
- Use validation utilities consistently
4. **API Interactions**
- Use the established composables for API calls
- Maintain proper error handling

View File

@ -0,0 +1,152 @@
# Process Execution - User Guide
## Introduction
The Process Execution module is the end-user interface of Corrad ProcessMaker, allowing users to interact with workflow processes that have been designed in the Process Builder. This module enables users to:
- Start new process instances
- View and complete assigned tasks
- Track the status and history of process instances
- Access process-related information and context
This guide provides a comprehensive overview of how to use the Process Execution module effectively.
## Getting Started
Access the Process Execution module by navigating to the "Process Execution" section in the main navigation menu. This section contains the following pages:
- **Execution Dashboard** - Overview of processes and tasks
- **New Case** - Start new process instances
- **Task Inbox** - View and manage assigned tasks
- **Case History** - View historical process instances
## Execution Dashboard
The Execution Dashboard provides a high-level overview of your process-related activities.
![Execution Dashboard](../assets/images/execution-dashboard.png)
### Dashboard Components
1. **Statistics Cards**
- **Pending Tasks** - Number of tasks awaiting your action
- **Active Cases** - Number of process instances currently running
- **Completed Cases** - Number of process instances that have completed
- **Overdue Tasks** - Number of tasks that have passed their due date
2. **Recent Tasks**
- Displays a list of your most recent tasks
- Shows task name, associated process, due date, and status
- Click on the "Open" button to go directly to the task
- Click on "View All Tasks" to navigate to the Task Inbox
3. **Recent Processes**
- Displays a list of recently started processes
- Shows process name, start date, and current status
- Click on "View" to see detailed information about the process
- Click on "View All Processes" to navigate to the Case History
## Starting a New Case
To initiate a new process instance, navigate to the "New Case" page from the Process Execution section.
![New Case](../assets/images/new-case.png)
### Steps to Start a New Case
1. **Browse Available Processes**
- All available processes are displayed as cards
- Each card shows the process name, description, category, average duration, and number of steps
- Processes are color-coded by category
2. **Filter and Search**
- Use the search box to find a specific process by name or description
- Use the category dropdown to filter processes by department (HR, Finance, Operations, etc.)
3. **Start a Process**
- Click the "Start Process" button on the desired process card
- You will be directed to the first form or task in the process
- Complete the form and submit to continue the process
## Managing Tasks in the Inbox
The Task Inbox displays all tasks assigned to you that require your action.
![Task Inbox](../assets/images/task-inbox.png)
### Task Inbox Features
1. **Filtering and Searching**
- Search for tasks by name, process, or case ID
- Filter tasks by process type
- Filter tasks by status (Pending, Overdue, Completed)
2. **Task Information**
- Each task displays its name, associated process, case ID, and due date
- Status indicators show whether a task is pending, overdue, or completed
- Click on "Open Task" to view and work on the task
3. **Refreshing the Inbox**
- Click the refresh button to update the task list
- Tasks are automatically updated when you complete an action
## Completing Tasks
When you open a task from the Inbox, you will see the Task Detail page.
![Task Detail](../assets/images/task-detail.png)
### Task Detail Components
1. **Task Information**
- Task name and description
- Process information and case ID
- Due date and other task metadata
2. **Task Form**
- Form fields required for task completion
- Field validation ensures correct data entry
- Submit button to complete the task
3. **Case Information**
- Expandable panel showing case variables
- Process timeline with status of each step
- Links to related documents or information
4. **Actions**
- Submit the form to complete the task
- Save draft to continue later
- View the case or process diagram
## Viewing Case History
The Case History page allows you to view all process instances (cases) and their current status.
![Case History](../assets/images/case-history.png)
### Case History Features
1. **Filtering and Searching**
- Search for cases by ID or process name
- Filter by process type
- Filter by status (Completed, Cancelled, Error)
- Filter by timeframe (Past Week, Past Month, Past Quarter, Past Year)
2. **Case Information**
- Each case displays its ID, process name, start date, completion date, and duration
- Status indicators show whether a case is completed, cancelled, or has encountered an error
- Click on "View Details" to see the complete case information
3. **Case Details**
- Timeline of all tasks and events in the case
- Case variables and their values
- Audit trail of user actions
- Related documents and notes
## Best Practices
- **Regular Check-ins**: Review your Task Inbox regularly to ensure timely completion of tasks
- **Proper Documentation**: When completing forms, provide thorough and accurate information
- **Process Awareness**: Familiarize yourself with the processes you participate in to understand your role
- **Communication**: Use comments or notes when available to communicate with other process participants
- **Organized Workflow**: Complete tasks in order of priority, focusing on overdue tasks first

32
layouts/execution.vue Normal file
View File

@ -0,0 +1,32 @@
<template>
<div class="min-h-screen bg-gray-50">
<!-- Top navigation -->
<div class="bg-white border-b border-gray-200">
<div class="container mx-auto px-4 py-3 flex items-center justify-between">
<div class="flex items-center space-x-8">
<NuxtLink to="/" class="text-lg font-bold">Corrad ProcessMaker</NuxtLink>
<div class="flex space-x-4">
<NuxtLink to="/execution" class="px-3 py-2 rounded hover:bg-gray-100">Dashboard</NuxtLink>
<NuxtLink to="/execution/new-case" class="px-3 py-2 rounded hover:bg-gray-100">New Case</NuxtLink>
<NuxtLink to="/execution/inbox" class="px-3 py-2 rounded hover:bg-gray-100">Inbox</NuxtLink>
<NuxtLink to="/execution/history" class="px-3 py-2 rounded hover:bg-gray-100">History</NuxtLink>
</div>
</div>
<div class="flex items-center space-x-4">
<div class="relative">
<button class="flex items-center text-gray-700 focus:outline-none">
<span class="mr-2">User Name</span>
<i class="material-symbols-outlined">account_circle</i>
</button>
</div>
</div>
</div>
</div>
<!-- Main content -->
<div class="container mx-auto px-4 py-6">
<slot />
</div>
</div>
</template>

View File

@ -108,4 +108,34 @@ export default [
}, },
], ],
}, },
{
header: "Process Execution",
description: "Execute and manage process workflows",
child: [
{
title: "Execution Dashboard",
path: "/execution",
icon: "ic:outline-dashboard",
child: [],
},
{
title: "New Case",
path: "/execution/new-case",
icon: "material-symbols:add-circle-outline",
child: [],
},
{
title: "Task Inbox",
path: "/execution/inbox",
icon: "material-symbols:inbox",
child: [],
},
{
title: "Case History",
path: "/execution/history",
icon: "material-symbols:history",
child: [],
},
],
},
]; ];

248
pages/execution/history.vue Normal file
View File

@ -0,0 +1,248 @@
<script setup>
definePageMeta({
title: "Case History",
layout: "default",
middleware: ["auth"],
requiresAuth: true,
});
// Case history data
const cases = ref([
{
id: "PO-2024-0098",
process: "Purchase Order Approval",
started: "Apr 10, 2024",
completed: "Apr 12, 2024",
duration: "2 days",
status: "COMPLETED",
action: { id: "PO-2024-0098" }
},
{
id: "LR-2024-0034",
process: "Leave Request",
started: "Apr 05, 2024",
completed: "Apr 06, 2024",
duration: "1 day",
status: "COMPLETED",
action: { id: "LR-2024-0034" }
},
{
id: "BM-2024-0045",
process: "Budget Management",
started: "Mar 28, 2024",
completed: "Apr 02, 2024",
duration: "5 days",
status: "COMPLETED",
action: { id: "BM-2024-0045" }
},
{
id: "IP-2024-0022",
process: "Invoice Processing",
started: "Mar 15, 2024",
completed: "Apr 15, 2024",
duration: "30 days",
status: "COMPLETED",
action: { id: "IP-2024-0022" }
},
{
id: "PO-2024-0056",
process: "Purchase Order Approval",
started: "Mar 02, 2024",
completed: "Mar 05, 2024",
duration: "3 days",
status: "CANCELLED",
action: { id: "PO-2024-0056" }
}
]);
// Filters
const searchQuery = ref("");
const selectedProcess = ref("");
const selectedStatus = ref("");
const selectedTimeframe = ref("");
// Process filter options
const processOptions = [
{ value: "", label: "All Processes" },
{ value: "Purchase Order Approval", label: "Purchase Order" },
{ value: "Leave Request", label: "Leave Request" },
{ value: "Budget Management", label: "Budget" },
{ value: "Invoice Processing", label: "Invoice" }
];
// Status filter options
const statusOptions = [
{ value: "", label: "All Statuses" },
{ value: "COMPLETED", label: "Completed" },
{ value: "CANCELLED", label: "Cancelled" },
{ value: "ERROR", label: "Error" }
];
// Timeframe filter options
const timeframeOptions = [
{ value: "", label: "All Time" },
{ value: "week", label: "Past Week" },
{ value: "month", label: "Past Month" },
{ value: "quarter", label: "Past Quarter" },
{ value: "year", label: "Past Year" }
];
// Filtered cases
const filteredCases = computed(() => {
return cases.value.filter(caseItem => {
const matchesSearch = searchQuery.value === "" ||
caseItem.id.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
caseItem.process.toLowerCase().includes(searchQuery.value.toLowerCase());
const matchesProcess = selectedProcess.value === "" ||
caseItem.process === selectedProcess.value;
const matchesStatus = selectedStatus.value === "" ||
caseItem.status === selectedStatus.value;
// Timeframe filtering would require actual date parsing
// Simplified for the example
const matchesTimeframe = selectedTimeframe.value === "";
return matchesSearch && matchesProcess && matchesStatus && matchesTimeframe;
});
});
// Table options
const tableOptions = {
striped: true,
hover: true,
bordered: false,
responsive: true
};
// Advanced table options
const optionsAdvanced = {
sortable: true,
filterable: false,
responsive: true,
outsideBorder: false
};
// Refresh cases
const refreshCases = () => {
// In a real app, this would fetch updated case data from the server
console.log("Refreshing cases...");
};
</script>
<template>
<div>
<LayoutsBreadcrumb />
<div class="mb-6">
<h1 class="text-2xl font-bold text-gray-800">Case History</h1>
<p class="text-gray-600">View your case history and completed processes.</p>
</div>
<!-- Filters and Search -->
<rs-card class="mb-6">
<template #body>
<div class="p-5 flex flex-wrap gap-4">
<div class="w-full md:w-1/2 lg:w-1/4">
<FormKit
type="text"
name="search"
placeholder="Search cases..."
prefix-icon="search"
v-model="searchQuery"
/>
</div>
<div class="w-full md:w-1/2 lg:w-1/4">
<FormKit
type="select"
name="process"
placeholder="Select process"
:options="processOptions"
v-model="selectedProcess"
/>
</div>
<div class="w-full md:w-1/2 lg:w-1/4">
<FormKit
type="select"
name="status"
placeholder="Select status"
:options="statusOptions"
v-model="selectedStatus"
/>
</div>
<div class="w-full md:w-1/2 lg:w-1/4">
<FormKit
type="select"
name="timeframe"
placeholder="Select timeframe"
:options="timeframeOptions"
v-model="selectedTimeframe"
/>
</div>
</div>
</template>
</rs-card>
<!-- Case History Table -->
<rs-card>
<template #header>
<div class="flex justify-between items-center p-5">
<h2 class="text-lg font-semibold">Your Cases</h2>
<div class="flex items-center space-x-2">
<rs-button
variant="text"
icon="material-symbols:refresh"
@click="refreshCases"
title="Refresh"
/>
<rs-button
variant="text"
icon="material-symbols:filter-list"
title="Filter"
/>
</div>
</div>
</template>
<template #body>
<div class="px-5 pb-5">
<rs-table
:data="filteredCases"
:options="tableOptions"
:options-advanced="optionsAdvanced"
advanced
>
<!-- Status column with custom rendering -->
<template v-slot:status="{ value }">
<div class="inline-flex">
<rs-badge
:variant="
value.status === 'COMPLETED'
? 'success'
: value.status === 'CANCELLED'
? 'warning'
: 'danger'
"
>
{{ value.status }}
</rs-badge>
</div>
</template>
<!-- Action column with custom rendering -->
<template v-slot:action="{ text }">
<rs-button
variant="secondary"
size="sm"
class="px-3 inline-flex items-center justify-center"
:to="`/execution/case/${text.id}`"
>
View Details
</rs-button>
</template>
</rs-table>
</div>
</template>
</rs-card>
</div>
</template>

248
pages/execution/inbox.vue Normal file
View File

@ -0,0 +1,248 @@
<script setup>
definePageMeta({
title: "Task Inbox",
layout: "default",
middleware: ["auth"],
requiresAuth: true,
});
// Task data
const tasks = ref([
{
id: "task-123",
name: "Complete Purchase Order Review",
process: "Purchase Order Approval",
caseId: "PO-2024-0123",
dueDate: "Apr 30, 2024",
assignedDate: "Apr 25, 2024",
status: "PENDING",
action: { id: "task-123" },
},
{
id: "task-124",
name: "Review Leave Request",
process: "Leave Approval",
caseId: "LR-2024-0056",
dueDate: "May 2, 2024",
assignedDate: "Apr 29, 2024",
status: "PENDING",
action: { id: "task-124" },
},
{
id: "task-125",
name: "Approve Budget Increase",
process: "Budget Management",
caseId: "BM-2024-0078",
dueDate: "Apr 28, 2024",
assignedDate: "Apr 20, 2024",
status: "OVERDUE",
action: { id: "task-125" },
},
{
id: "task-126",
name: "Review IT Service Request",
process: "IT Service Request",
caseId: "IT-2024-0092",
dueDate: "May 5, 2024",
assignedDate: "Apr 28, 2024",
status: "PENDING",
action: { id: "task-126" },
},
{
id: "task-127",
name: "Complete Invoice Processing",
process: "Invoice Processing",
caseId: "IP-2024-0045",
dueDate: "Apr 26, 2024",
assignedDate: "Apr 24, 2024",
status: "COMPLETED",
action: { id: "task-127" },
},
]);
// Filters
const searchQuery = ref("");
const selectedProcess = ref("");
const selectedStatus = ref("");
// Process filter options
const processOptions = [
{ value: "", label: "All Processes" },
{ value: "Purchase Order Approval", label: "Purchase Order" },
{ value: "Leave Approval", label: "Leave Request" },
{ value: "Budget Management", label: "Budget" },
{ value: "IT Service Request", label: "IT Service" },
{ value: "Invoice Processing", label: "Invoice" },
];
// Status filter options
const statusOptions = [
{ value: "", label: "All Statuses" },
{ value: "PENDING", label: "Pending" },
{ value: "OVERDUE", label: "Overdue" },
{ value: "COMPLETED", label: "Completed" },
];
// Filtered tasks
const filteredTasks = computed(() => {
return tasks.value.filter((task) => {
const matchesSearch =
searchQuery.value === "" ||
task.name.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
task.process.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
task.caseId.toLowerCase().includes(searchQuery.value.toLowerCase());
const matchesProcess =
selectedProcess.value === "" || task.process === selectedProcess.value;
const matchesStatus =
selectedStatus.value === "" || task.status === selectedStatus.value;
return matchesSearch && matchesProcess && matchesStatus;
});
});
// Table options
const tableOptions = {
striped: true,
hover: true,
bordered: false,
responsive: true,
};
// Advanced table options
const optionsAdvanced = {
sortable: true,
filterable: false,
responsive: true,
outsideBorder: false,
};
// Refresh tasks
const refreshTasks = () => {
// In a real app, this would fetch updated task data
console.log("Refreshing tasks...");
};
</script>
<template>
<div>
<LayoutsBreadcrumb />
<!-- Filters and Search -->
<rs-card class="mb-6">
<template #body>
<div class="p-5 flex flex-wrap gap-4">
<div class="w-full md:w-1/3">
<FormKit
type="text"
name="search"
placeholder="Search tasks..."
prefix-icon="search"
v-model="searchQuery"
/>
</div>
<div class="w-full md:w-1/3">
<FormKit
type="select"
name="process"
placeholder="Select process"
:options="processOptions"
v-model="selectedProcess"
/>
</div>
<div class="w-full md:w-1/3">
<FormKit
type="select"
name="status"
placeholder="Select status"
:options="statusOptions"
v-model="selectedStatus"
/>
</div>
</div>
</template>
</rs-card>
<!-- Task List -->
<rs-card>
<template #header>
<div class="flex justify-between items-center p-5">
<h2 class="text-lg font-semibold">Your Tasks</h2>
<div class="flex items-center space-x-2">
<rs-button
variant="text"
icon="material-symbols:refresh"
@click="refreshTasks"
title="Refresh"
/>
<rs-button
variant="text"
icon="material-symbols:filter-list"
title="Filter"
/>
</div>
</div>
</template>
<template #body>
<div class="px-5 pb-5">
<rs-table
:data="filteredTasks"
:options="tableOptions"
:options-advanced="optionsAdvanced"
advanced
>
<!-- Name column with custom rendering -->
<template v-slot:name="{ value, text }">
<div>
<div class="font-medium">{{ value.caseId }}</div>
<div class="text-sm text-gray-600">
Case #{{ value.caseId }}
</div>
</div>
</template>
<!-- Due Date column with custom rendering -->
<template v-slot:dueDate="{ value, text }">
<div v-if="value.status === 'COMPLETED'" class="text-gray-600">
Completed: {{ value.dueDate }}
</div>
<div v-else>
{{ value.dueDate }}
</div>
</template>
<!-- Status column with custom rendering -->
<template v-slot:status="{ value }">
<div class="inline-flex">
<rs-badge
:variant="
value.status === 'PENDING'
? 'warning'
: value.status === 'OVERDUE'
? 'danger'
: 'success'
"
>
{{ value.status }}
</rs-badge>
</div>
</template>
<!-- Action column with custom rendering -->
<template v-slot:action="{ value }">
<rs-button
variant="secondary"
size="sm"
class="px-3 inline-flex items-center justify-center"
>
<nuxt-link :to="`/execution/task/${value.id}`">
Open Task
</nuxt-link>
</rs-button>
</template>
</rs-table>
</div>
</template>
</rs-card>
</div>
</template>

287
pages/execution/index.vue Normal file
View File

@ -0,0 +1,287 @@
<script setup>
definePageMeta({
title: "Process Execution Dashboard",
layout: "default",
middleware: ["auth"],
requiresAuth: true,
});
// Mock data for pending tasks
const pendingTasks = ref(12);
const activeCases = ref(7);
const completedCases = ref(23);
const overdueTasks = ref(5);
// Mock data for recent tasks
const recentTasks = ref([
{
name: "Complete Purchase Order Review",
process: "Purchase Order Approval",
dueDate: "Apr 30, 2024",
status: "PENDING",
action: { id: "task-123" },
},
{
name: "Review Leave Request",
process: "Leave Approval",
dueDate: "May 2, 2024",
status: "PENDING",
action: { id: "task-124" },
},
{
name: "Approve Budget Increase",
process: "Budget Management",
dueDate: "Apr 28, 2024",
status: "OVERDUE",
action: { id: "task-125" },
},
]);
// Mock data for recent processes
const recentProcesses = ref([
{
name: "Purchase Order Approval",
started: "Apr 25, 2024",
status: "ACTIVE",
action: { id: "case-123" },
},
{
name: "Leave Approval",
started: "Apr 29, 2024",
status: "ACTIVE",
action: { id: "case-124" },
},
{
name: "Invoice Processing",
started: "Apr 15, 2024",
status: "COMPLETED",
action: { id: "case-125" },
},
]);
// Table options
const tableOptions = {
striped: true,
hover: true,
responsive: true,
search: false,
pagination: false,
};
// Advanced table options
const optionsAdvanced = {
sortable: true,
filterable: false,
responsive: true,
outsideBorder: false,
};
</script>
<template>
<div>
<LayoutsBreadcrumb />
<!-- Stats -->
<div class="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-4 gap-x-6 mb-6">
<!-- Pending Tasks -->
<rs-card>
<template #body>
<div class="pt-5 pb-3 px-5 flex items-center gap-4">
<div
class="p-5 flex justify-center items-center bg-yellow-100 rounded-2xl"
>
<Icon
class="text-yellow-500"
name="material-symbols:inbox"
></Icon>
</div>
<div class="flex-1 truncate">
<span class="block font-semibold text-xl leading-tight">{{
pendingTasks
}}</span>
<span class="text-base font-semibold text-gray-500"
>Pending Tasks</span
>
</div>
</div>
</template>
</rs-card>
<!-- Active Cases -->
<rs-card>
<template #body>
<div class="pt-5 pb-3 px-5 flex items-center gap-4">
<div
class="p-5 flex justify-center items-center bg-blue-100 rounded-2xl"
>
<Icon
class="text-blue-500"
name="material-symbols:play-circle-outline"
></Icon>
</div>
<div class="flex-1 truncate">
<span class="block font-semibold text-xl leading-tight">{{
activeCases
}}</span>
<span class="text-base font-semibold text-gray-500"
>Active Cases</span
>
</div>
</div>
</template>
</rs-card>
<!-- Completed Cases -->
<rs-card>
<template #body>
<div class="pt-5 pb-3 px-5 flex items-center gap-4">
<div
class="p-5 flex justify-center items-center bg-green-100 rounded-2xl"
>
<Icon
class="text-green-500"
name="material-symbols:check-circle-outline"
></Icon>
</div>
<div class="flex-1 truncate">
<span class="block font-semibold text-xl leading-tight">{{
completedCases
}}</span>
<span class="text-base font-semibold text-gray-500"
>Completed Cases</span
>
</div>
</div>
</template>
</rs-card>
<!-- Overdue Tasks -->
<rs-card>
<template #body>
<div class="pt-5 pb-3 px-5 flex items-center gap-4">
<div
class="p-5 flex justify-center items-center bg-red-100 rounded-2xl"
>
<Icon
class="text-red-500"
name="material-symbols:warning-outline"
></Icon>
</div>
<div class="flex-1 truncate">
<span
class="block font-semibold text-xl leading-tight text-red-500"
>{{ overdueTasks }}</span
>
<span class="text-base font-semibold text-gray-500"
>Overdue Tasks</span
>
</div>
</div>
</template>
</rs-card>
</div>
<!-- Recent Tasks -->
<rs-card class="mb-6">
<template #header>
<div class="flex justify-between items-center p-5">
<h2 class="text-lg font-semibold">Recent Tasks</h2>
<rs-button variant="primary" size="sm" to="/execution/inbox">
View All Tasks
</rs-button>
</div>
</template>
<template #body>
<div class="px-5 pb-5">
<rs-table
:data="recentTasks"
:options="tableOptions"
:options-advanced="optionsAdvanced"
advanced
>
<!-- Status column with custom rendering -->
<template v-slot:status="{ value }">
<div class="inline-flex">
<rs-badge
:variant="
value.status === 'PENDING'
? 'warning'
: value.status === 'OVERDUE'
? 'danger'
: 'success'
"
>
{{ value.status }}
</rs-badge>
</div>
</template>
<!-- Action column with custom rendering -->
<template v-slot:action="{ value }">
<rs-button
variant="secondary"
size="sm"
class="px-3 inline-flex items-center justify-center"
>
<nuxt-link :to="`/execution/task/${value.id}`">
Open
</nuxt-link>
</rs-button>
</template>
</rs-table>
</div>
</template>
</rs-card>
<!-- Recent Processes -->
<rs-card>
<template #header>
<div class="flex justify-between items-center p-5">
<h2 class="text-lg font-semibold">Recent Processes</h2>
<rs-button variant="primary" size="sm" to="/execution/history">
View All Processes
</rs-button>
</div>
</template>
<template #body>
<div class="px-5 pb-5">
<rs-table
:data="recentProcesses"
:options="tableOptions"
:options-advanced="optionsAdvanced"
advanced
>
<!-- Status column with custom rendering -->
<template v-slot:status="{ value }">
<div class="inline-flex">
<rs-badge
:variant="
value.status === 'ACTIVE'
? 'primary'
: value.status === 'COMPLETED'
? 'success'
: 'warning'
"
>
{{ value.status }}
</rs-badge>
</div>
</template>
<!-- Action column with custom rendering -->
<template v-slot:action="{ text }">
<rs-button
variant="secondary"
size="sm"
class="px-3 inline-flex items-center justify-center"
:to="`/execution/case/${text.id}`"
>
View
</rs-button>
</template>
</rs-table>
</div>
</template>
</rs-card>
</div>
</template>

View File

@ -0,0 +1,173 @@
<template>
<div>
<LayoutsBreadcrumb />
<!-- Search and Filter -->
<rs-card>
<div class="p-5 flex flex-wrap gap-4">
<div class="w-full md:w-1/2">
<FormKit
type="text"
name="search"
placeholder="Search processes..."
prefix-icon="search"
v-model="searchQuery"
/>
</div>
<div class="w-full md:w-1/3">
<FormKit
type="select"
name="category"
placeholder="Select category"
:options="categories"
v-model="selectedCategory"
/>
</div>
</div>
</rs-card>
<!-- Process Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<rs-card
v-for="process in filteredProcesses"
:key="process.id"
class="overflow-hidden hover:shadow-md transition-shadow duration-300"
>
<div :class="`h-3 bg-${process.color}-500`"></div>
<template #body>
<div class="p-5">
<div class="flex justify-between items-start mb-4">
<h3 class="text-lg font-semibold">{{ process.name }}</h3>
<rs-badge
:variant="
process.category === 'HR'
? 'info'
: process.category === 'Finance'
? 'success'
: 'warning'
"
>
{{ process.category }}
</rs-badge>
</div>
<p class="text-gray-600 text-sm mb-4">{{ process.description }}</p>
<div class="text-xs text-gray-500 mb-4">
<div class="flex items-center mb-1">
<Icon
class="text-base mr-1"
name="material-symbols:schedule"
></Icon>
<span>Average duration: {{ process.duration }}</span>
</div>
<div class="flex items-center">
<Icon
class="text-base mr-1"
name="material-symbols:sync"
></Icon>
<span>{{ process.steps }} steps</span>
</div>
</div>
<div class="mt-4">
<rs-button
variant="primary"
block
@click="startProcess(process.id)"
>
Start Process
</rs-button>
</div>
</div>
</template>
</rs-card>
</div>
</div>
</template>
<script setup>
definePageMeta({
title: "Start New Case",
layout: "default",
middleware: ["auth"],
requiresAuth: true,
});
// Mock data for processes
const processes = ref([
{
id: 1,
name: "Purchase Order Approval",
description:
"Process for approving purchase orders submitted by departments.",
category: "Finance",
duration: "3 days",
steps: 10,
color: "blue",
},
{
id: 2,
name: "Leave Request",
description:
"Process for submitting and approving employee leave requests.",
category: "HR",
duration: "1 day",
steps: 5,
color: "green",
},
{
id: 3,
name: "Budget Request",
description:
"Process for requesting and approving department budget allocations.",
category: "Finance",
duration: "7 days",
steps: 12,
color: "purple",
},
{
id: 4,
name: "IT Service Request",
description:
"Process for submitting and handling IT service and support requests.",
category: "Operations",
duration: "2 days",
steps: 7,
color: "yellow",
},
]);
// Search and filter
const searchQuery = ref("");
const selectedCategory = ref("");
// Categories for filter
const categories = [
{ value: "", label: "All Categories" },
{ value: "HR", label: "Human Resources" },
{ value: "Finance", label: "Finance" },
{ value: "Operations", label: "Operations" },
];
// Filtered processes
const filteredProcesses = computed(() => {
return processes.value.filter((process) => {
const matchesSearch =
searchQuery.value === "" ||
process.name.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
process.description
.toLowerCase()
.includes(searchQuery.value.toLowerCase());
const matchesCategory =
selectedCategory.value === "" ||
process.category === selectedCategory.value;
return matchesSearch && matchesCategory;
});
});
// Start a process
const startProcess = (processId) => {
// Logic to start a process would go here
console.log("Starting process:", processId);
};
</script>

View File

@ -0,0 +1,271 @@
<template>
<div>
<LayoutsBreadcrumb />
<!-- Task Form -->
<!-- <rs-card class="mb-6">
<template #body>
<div class="p-5">
<TaskForm :task="currentTask" />
</div>
</template>
</rs-card> -->
<div class="mb-6">
<TaskForm :task="currentTask" />
</div>
<!-- Case Information Accordion -->
<rs-card>
<template #header>
<div class="flex justify-between items-center">
<h2 class="text-lg font-semibold">Case Information</h2>
<button
@click="toggleCaseInfo"
class="text-gray-500 hover:text-gray-700 p-2"
>
<Icon
:name="
showCaseInfo
? 'material-symbols:expand-less'
: 'material-symbols:expand-more'
"
/>
</button>
</div>
</template>
<template #body v-if="showCaseInfo">
<div class="">
<!-- Case Variables -->
<div class="mb-6">
<h3 class="text-sm font-medium text-gray-700 mb-3">
Case Variables
</h3>
<div class="border border-gray-200 rounded-md overflow-hidden">
<rs-table
:data="caseVariables"
:columns="variableColumns"
:options="tableOptions"
:options-advanced="optionsAdvanced"
advanced
/>
</div>
</div>
<!-- Case Timeline -->
<div>
<h3 class="text-sm font-medium text-gray-700 mb-3">
Case Timeline
</h3>
<div class="flow-root">
<ul class="mb-2">
<li v-for="(event, index) in timeline" :key="index">
<div class="relative pb-8" v-if="index < timeline.length - 1">
<span
class="absolute top-4 left-4 -ml-px h-full w-0.5 bg-gray-200"
aria-hidden="true"
></span>
<div class="relative flex space-x-3">
<div>
<span
class="h-8 w-8 rounded-full flex items-center justify-center"
:class="eventColorClass(event.type)"
>
<Icon
:name="eventIcon(event.type)"
class="text-white text-sm"
/>
</span>
</div>
<div
class="min-w-0 flex-1 pt-1.5 flex justify-between space-x-4"
>
<div>
<p
class="text-sm text-gray-700"
v-html="event.description"
></p>
</div>
<div
class="text-right text-sm whitespace-nowrap text-gray-500"
>
{{ event.date }}
</div>
</div>
</div>
</div>
<div class="relative" v-else>
<div class="relative flex space-x-3">
<div>
<span
class="h-8 w-8 rounded-full flex items-center justify-center"
:class="eventColorClass(event.type)"
>
<Icon
:name="eventIcon(event.type)"
class="text-white text-sm"
/>
</span>
</div>
<div
class="min-w-0 flex-1 pt-1.5 flex justify-between space-x-4"
>
<div>
<p
class="text-sm text-gray-700"
v-html="event.description"
></p>
</div>
<div
class="text-right text-sm whitespace-nowrap text-gray-500"
>
{{ event.date }}
</div>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</template>
</rs-card>
</div>
</template>
<script setup>
definePageMeta({
title: "Task Details",
layout: "default",
middleware: ["auth"],
requiresAuth: true,
});
// Mock task data (would come from API in real implementation)
const currentTask = ref({
id: "task-123",
name: "Complete Purchase Order Review",
process: "Purchase Order Approval",
caseId: "PO-2024-0123",
status: "pending",
dueDate: "Apr 30, 2024",
instructions:
"Please review the purchase order details and either approve or reject the request. If rejecting, please provide a reason in the comments section.",
});
// Toggle case information section
const showCaseInfo = ref(true);
const toggleCaseInfo = () => {
showCaseInfo.value = !showCaseInfo.value;
};
// Case variables
const caseVariables = ref([
{
name: "purchaseOrderNumber",
value: "PO-2024-0123",
type: "String",
},
{
name: "amount",
value: "5250.00",
type: "Number",
},
{
name: "department",
value: "IT Department",
type: "String",
},
{
name: "vendor",
value: "Acme Computing Supplies",
type: "String",
},
{
name: "approvalRequired",
value: "true",
type: "Boolean",
},
]);
// Variable columns for table
const variableColumns = [
{ key: "name", label: "Name" },
{ key: "value", label: "Value" },
{ key: "type", label: "Type" },
];
// Table options
const tableOptions = {
striped: true,
hover: true,
bordered: false,
responsive: true,
};
// Advanced table options
const optionsAdvanced = {
sortable: true,
filterable: false,
responsive: true,
outsideBorder: false,
};
// Case timeline
const timeline = ref([
{
type: "start",
description:
'Process started by <span class="font-medium">John Smith</span>',
date: "Apr 25, 2024",
},
{
type: "complete",
description:
'Form <span class="font-medium">"New Purchase Order"</span> completed',
date: "Apr 25, 2024",
},
{
type: "assign",
description:
'Task <span class="font-medium">"Manager Review"</span> assigned to <span class="font-medium">Jane Doe</span>',
date: "Apr 25, 2024",
},
{
type: "current",
description:
'Task <span class="font-medium">"Complete Purchase Order Review"</span> waiting',
date: "Current",
},
]);
// Helper functions for timeline
const eventColorClass = (type) => {
switch (type) {
case "start":
return "bg-blue-500";
case "complete":
return "bg-green-500";
case "assign":
case "current":
return "bg-yellow-500";
default:
return "bg-gray-500";
}
};
const eventIcon = (type) => {
switch (type) {
case "start":
return "material-symbols:play-arrow";
case "complete":
return "material-symbols:task-alt";
case "assign":
case "current":
return "material-symbols:pending";
default:
return "material-symbols:info";
}
};
</script>