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:
parent
2136aecdbd
commit
0a4d41df06
135
components/TaskForm.vue
Normal file
135
components/TaskForm.vue
Normal 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>
|
@ -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
|
||||
- [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
|
||||
|
||||
New to the project? We recommend reading the documentation in this order:
|
||||
|
@ -68,6 +68,27 @@ The Form Builder complements the Process Builder, enabling users to create forms
|
||||
- Form versioning and management
|
||||
- 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
|
||||
|
||||
### 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
|
||||
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
|
||||
|
||||
1. Process execution begins at a start event
|
||||
|
278
doc/process-execution/TECHNICAL_GUIDE.md
Normal file
278
doc/process-execution/TECHNICAL_GUIDE.md
Normal 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
|
152
doc/process-execution/USER_GUIDE.md
Normal file
152
doc/process-execution/USER_GUIDE.md
Normal 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.
|
||||
|
||||

|
||||
|
||||
### 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.
|
||||
|
||||

|
||||
|
||||
### 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 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 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 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
32
layouts/execution.vue
Normal 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>
|
@ -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
248
pages/execution/history.vue
Normal 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
248
pages/execution/inbox.vue
Normal 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
287
pages/execution/index.vue
Normal 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>
|
173
pages/execution/new-case.vue
Normal file
173
pages/execution/new-case.vue
Normal 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>
|
271
pages/execution/task/[id].vue
Normal file
271
pages/execution/task/[id].vue
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user