From ae806911bec64f2cd75837b71ddb524d585e4bcb Mon Sep 17 00:00:00 2001
From: mahdahar <89adham@gmail.com>
Date: Tue, 24 Feb 2026 16:53:04 +0700
Subject: [PATCH] feat(equipment,organization): add equipment API client and
complete organization module structure
- Add equipment.js API client with full CRUD operations
- Add organization sub-routes: account, department, discipline, instrument, site, workstation
- Create EquipmentModal and DeleteConfirmModal components
- Update master-data navigation and sidebar
- Update tests, containers, counters, geography, locations, occupations, specialties, testmap, and valuesets pages
- Add COMPONENT_ORGANIZATION.md documentation
---
AGENTS.md | 141 ++--
COMPONENT_ORGANIZATION.md | 155 ++++
docs/api-docs.bundled.yaml | 688 +++++++++++++++-
src/lib/api/equipment.js | 86 ++
src/lib/components/Sidebar.svelte | 49 +-
src/routes/(app)/master-data/+page.svelte | 12 +-
.../(app)/master-data/contacts/+page.svelte | 34 +-
.../(app)/master-data/containers/+page.svelte | 8 +-
.../(app)/master-data/counters/+page.svelte | 10 +-
.../(app)/master-data/geography/+page.svelte | 24 +-
.../(app)/master-data/locations/+page.svelte | 8 +-
.../master-data/occupations/+page.svelte | 8 +-
.../master-data/organization/+page.svelte | 735 ++----------------
.../organization/account/+page.svelte | 278 +++++++
.../organization/department/+page.svelte | 320 ++++++++
.../organization/discipline/+page.svelte | 307 ++++++++
.../organization/instrument/+page.svelte | 281 +++++++
.../instrument/DeleteConfirmModal.svelte | 43 +
.../instrument/EquipmentModal.svelte | 155 ++++
.../organization/site/+page.svelte | 265 +++++++
.../organization/workstation/+page.svelte | 265 +++++++
.../master-data/specialties/+page.svelte | 36 +-
.../(app)/master-data/testmap/+page.svelte | 111 ++-
.../master-data/testmap/TestMapModal.svelte | 7 +-
.../(app)/master-data/tests/+page.svelte | 34 +-
.../(app)/master-data/valuesets/+page.svelte | 8 +-
26 files changed, 3154 insertions(+), 914 deletions(-)
create mode 100644 COMPONENT_ORGANIZATION.md
create mode 100644 src/lib/api/equipment.js
create mode 100644 src/routes/(app)/master-data/organization/account/+page.svelte
create mode 100644 src/routes/(app)/master-data/organization/department/+page.svelte
create mode 100644 src/routes/(app)/master-data/organization/discipline/+page.svelte
create mode 100644 src/routes/(app)/master-data/organization/instrument/+page.svelte
create mode 100644 src/routes/(app)/master-data/organization/instrument/DeleteConfirmModal.svelte
create mode 100644 src/routes/(app)/master-data/organization/instrument/EquipmentModal.svelte
create mode 100644 src/routes/(app)/master-data/organization/site/+page.svelte
create mode 100644 src/routes/(app)/master-data/organization/workstation/+page.svelte
diff --git a/AGENTS.md b/AGENTS.md
index 3cb17f6..abd99a2 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -5,13 +5,22 @@ SvelteKit frontend for Clinical Laboratory Quality Management System. Uses Svelt
## Commands
```bash
-pnpm run dev # Development server
-pnpm run build # Production build
+# Development
+pnpm run dev # Start development server
+pnpm run build # Production build (outputs to build/)
pnpm run preview # Preview production build
-pnpm run prepare # Sync SvelteKit
+pnpm run prepare # Sync SvelteKit (runs on install)
+
+# Package management
+pnpm install # Install dependencies (use pnpm, not npm/yarn)
+
+# Testing (not configured yet - add when needed)
+# vitest run src/path/to/test.js # Run single test
+# vitest # Run tests in watch mode
+# npx playwright test # E2E tests
```
-**No test framework yet.** When adding: use Vitest (`vitest run src/path/to/test.js`), Playwright for E2E.
+**No ESLint/Prettier configured yet.** When adding: configure in `vite.config.js` or separate config files.
## Code Style
@@ -20,26 +29,26 @@ pnpm run prepare # Sync SvelteKit
- **Quotes**: Single quotes
- **Indentation**: 2 spaces
- **Trailing commas**: In multi-line objects/arrays
-- **JSDoc**: Document all exported functions
+- **JSDoc**: Document all exported functions with `@param` and `@returns`
-## Naming Conventions
-
-- **Components**: PascalCase (`LoginForm.svelte`)
-- **Files/Routes**: lowercase with hyphens (`+page.svelte`)
-- **Variables**: camelCase (`isLoading`, `userName`)
-- **Constants**: UPPER_SNAKE_CASE (`API_URL`)
-- **Stores**: camelCase (`auth`, `config`)
-- **Handlers**: prefix with `handle` (`handleSubmit`)
-- **Form state**: `formLoading`, `formError`
-
-## Imports Order
+### Imports Order
1. Svelte (`svelte`, `$app/*`)
2. `$lib/*` (stores, api, components, utils)
3. External libraries (`lucide-svelte`)
4. Relative imports (minimize, prefer `$lib`)
-## Svelte 5 Components
+## Naming Conventions
+
+- **Components**: PascalCase (`LoginForm.svelte`, `PatientFormModal.svelte`)
+- **Files/Routes**: lowercase with hyphens (`+page.svelte`, `user-profile/`)
+- **Variables**: camelCase (`isLoading`, `userName`)
+- **Constants**: UPPER_SNAKE_CASE (`API_URL`, `STORAGE_KEY`)
+- **Stores**: camelCase, descriptive (`auth`, `config`, `userStore`)
+- **Event handlers**: prefix with `handle` (`handleSubmit`, `handleClick`)
+- **Form state**: `formLoading`, `formError`, `deleteConfirmOpen`
+
+## Svelte 5 Component Structure
```svelte
+
+
+ {#snippet children()}
+
+
+
+
+
+
+ {#if activeTab === 'basic'}
+
+ {:else if activeTab === 'technical'}
+
+ {:else if activeTab === 'calculation'}
+
+ {/if}
+ {/snippet}
+
+```
+
+```svelte
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Data Flow
+
+### Parent to Child
+- Pass data via props (`bind:formData`)
+- Use `$bindable()` for two-way binding
+- Keep state in parent when shared across tabs
+
+### Child to Parent
+- Use callbacks for actions (`onSave`, `onClose`)
+- Modify bound data directly (with `$bindable`)
+- Emit events for complex interactions
+
+## Props Interface Pattern
+
+```javascript
+// Define props with JSDoc
+/** @type {{ formData: Object, onValidate: Function, readonly: boolean }} */
+let {
+ formData = $bindable({}),
+ onValidate = () => true,
+ readonly = false
+} = $props();
+```
+
+## Naming Conventions
+
+- **Main modal**: `{Feature}Modal.svelte` (e.g., `TestFormModal.svelte`)
+- **Tab components**: `{TabName}Tab.svelte` (e.g., `BasicInfoTab.svelte`)
+- **Nested modals**: `{Action}Modal.svelte` (e.g., `ConfirmDeleteModal.svelte`)
+- **Folder names**: kebab-case matching the modal name (e.g., `test-modal/`)
+
+## Shared State Management
+
+For complex modals with shared state across tabs:
+
+```javascript
+// In main modal
+let sharedState = $state({
+ dirty: false,
+ errors: {},
+ selectedItems: []
+});
+
+// Pass to tabs
+
+```
+
+## Import Order in Sub-components
+
+Same as main components:
+1. Svelte imports
+2. `$lib/*` imports
+3. External libraries
+4. Relative imports (other tabs/modals)
+
+## Testing Split Components
+
+```bash
+# Test individual tab component
+vitest run src/routes/feature/modal-tabs/BasicInfoTab.test.js
+
+# Test main modal integration
+vitest run src/routes/feature/FeatureModal.test.js
+```
+
+## Benefits
+
+- **Maintainability**: Each file has single responsibility
+- **Collaboration**: Multiple developers can work on different tabs
+- **Testing**: Test individual sections in isolation
+- **Performance**: Only render visible tab content
+- **Reusability**: Tabs can be used in different modals
diff --git a/docs/api-docs.bundled.yaml b/docs/api-docs.bundled.yaml
index 69f3bfe..098ec39 100644
--- a/docs/api-docs.bundled.yaml
+++ b/docs/api-docs.bundled.yaml
@@ -47,6 +47,8 @@ tags:
description: Value set definitions and items
- name: Demo
description: Demo/test endpoints (no authentication)
+ - name: EquipmentList
+ description: Laboratory equipment and instrument management
paths:
/api/auth/login:
post:
@@ -594,6 +596,225 @@ paths:
responses:
'200':
description: Status logged
+ /api/equipmentlist:
+ get:
+ tags:
+ - EquipmentList
+ summary: List equipment
+ description: Get list of equipment with optional filters
+ security:
+ - bearerAuth: []
+ parameters:
+ - name: IEID
+ in: query
+ schema:
+ type: string
+ description: Filter by IEID
+ - name: InstrumentName
+ in: query
+ schema:
+ type: string
+ description: Filter by instrument name
+ - name: DepartmentID
+ in: query
+ schema:
+ type: integer
+ description: Filter by department ID
+ - name: WorkstationID
+ in: query
+ schema:
+ type: integer
+ description: Filter by workstation ID
+ - name: Enable
+ in: query
+ schema:
+ type: integer
+ enum:
+ - 0
+ - 1
+ description: Filter by enable status
+ responses:
+ '200':
+ description: List of equipment
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ message:
+ type: string
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/EquipmentList'
+ post:
+ tags:
+ - EquipmentList
+ summary: Create equipment
+ description: Create a new equipment entry
+ security:
+ - bearerAuth: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - IEID
+ - DepartmentID
+ - Enable
+ - EquipmentRole
+ properties:
+ IEID:
+ type: string
+ maxLength: 50
+ DepartmentID:
+ type: integer
+ InstrumentID:
+ type: string
+ maxLength: 150
+ InstrumentName:
+ type: string
+ maxLength: 150
+ WorkstationID:
+ type: integer
+ Enable:
+ type: integer
+ enum:
+ - 0
+ - 1
+ EquipmentRole:
+ type: string
+ maxLength: 1
+ responses:
+ '201':
+ description: Equipment created
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ message:
+ type: string
+ data:
+ type: integer
+ patch:
+ tags:
+ - EquipmentList
+ summary: Update equipment
+ description: Update an existing equipment entry
+ security:
+ - bearerAuth: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - EID
+ properties:
+ EID:
+ type: integer
+ IEID:
+ type: string
+ maxLength: 50
+ DepartmentID:
+ type: integer
+ InstrumentID:
+ type: string
+ maxLength: 150
+ InstrumentName:
+ type: string
+ maxLength: 150
+ WorkstationID:
+ type: integer
+ Enable:
+ type: integer
+ enum:
+ - 0
+ - 1
+ EquipmentRole:
+ type: string
+ maxLength: 1
+ responses:
+ '200':
+ description: Equipment updated
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ message:
+ type: string
+ data:
+ type: integer
+ delete:
+ tags:
+ - EquipmentList
+ summary: Delete equipment
+ description: Soft delete an equipment entry
+ security:
+ - bearerAuth: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - EID
+ properties:
+ EID:
+ type: integer
+ responses:
+ '200':
+ description: Equipment deleted
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ message:
+ type: string
+ /api/equipmentlist/{id}:
+ get:
+ tags:
+ - EquipmentList
+ summary: Get equipment by ID
+ description: Get a single equipment entry by its EID
+ security:
+ - bearerAuth: []
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: integer
+ description: Equipment ID
+ responses:
+ '200':
+ description: Equipment details
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ message:
+ type: string
+ data:
+ $ref: '#/components/schemas/EquipmentList'
/api/location:
get:
tags:
@@ -2556,6 +2777,326 @@ paths:
responses:
'200':
description: Collection method details
+ /api/test/testmap:
+ get:
+ tags:
+ - Tests
+ summary: List all test mappings
+ security:
+ - bearerAuth: []
+ parameters:
+ - name: page
+ in: query
+ schema:
+ type: integer
+ default: 1
+ description: Page number for pagination
+ - name: perPage
+ in: query
+ schema:
+ type: integer
+ default: 20
+ description: Number of items per page
+ responses:
+ '200':
+ description: List of test mappings
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ example: success
+ message:
+ type: string
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/TestMap'
+ post:
+ tags:
+ - Tests
+ summary: Create test mapping
+ security:
+ - bearerAuth: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ TestSiteID:
+ type: integer
+ description: Test Site ID (required)
+ HostType:
+ type: string
+ description: Host type code
+ HostID:
+ type: string
+ description: Host identifier
+ HostTestCode:
+ type: string
+ description: Test code in host system
+ HostTestName:
+ type: string
+ description: Test name in host system
+ ClientType:
+ type: string
+ description: Client type code
+ ClientID:
+ type: string
+ description: Client identifier
+ ConDefID:
+ type: integer
+ description: Connection definition ID
+ ClientTestCode:
+ type: string
+ description: Test code in client system
+ ClientTestName:
+ type: string
+ description: Test name in client system
+ required:
+ - TestSiteID
+ responses:
+ '201':
+ description: Test mapping created
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ example: success
+ message:
+ type: string
+ data:
+ type: integer
+ description: Created TestMapID
+ patch:
+ tags:
+ - Tests
+ summary: Update test mapping
+ security:
+ - bearerAuth: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ TestMapID:
+ type: integer
+ description: Test Map ID (required)
+ TestSiteID:
+ type: integer
+ HostType:
+ type: string
+ HostID:
+ type: string
+ HostTestCode:
+ type: string
+ HostTestName:
+ type: string
+ ClientType:
+ type: string
+ ClientID:
+ type: string
+ ConDefID:
+ type: integer
+ ClientTestCode:
+ type: string
+ ClientTestName:
+ type: string
+ required:
+ - TestMapID
+ responses:
+ '200':
+ description: Test mapping updated
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ example: success
+ message:
+ type: string
+ data:
+ type: integer
+ description: Updated TestMapID
+ delete:
+ tags:
+ - Tests
+ summary: Soft delete test mapping
+ security:
+ - bearerAuth: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ TestMapID:
+ type: integer
+ description: Test Map ID to delete (required)
+ required:
+ - TestMapID
+ responses:
+ '200':
+ description: Test mapping deleted successfully
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ example: success
+ message:
+ type: string
+ data:
+ type: integer
+ description: Deleted TestMapID
+ '404':
+ description: Test mapping not found or already deleted
+ /api/test/testmap/{id}:
+ get:
+ tags:
+ - Tests
+ summary: Get test mapping by ID
+ security:
+ - bearerAuth: []
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: integer
+ description: Test Map ID
+ responses:
+ '200':
+ description: Test mapping details
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ message:
+ type: string
+ data:
+ $ref: '#/components/schemas/TestMap'
+ '404':
+ description: Test mapping not found
+ /api/test/testmap/by-testsite/{testSiteID}:
+ get:
+ tags:
+ - Tests
+ summary: Get test mappings by test site
+ security:
+ - bearerAuth: []
+ parameters:
+ - name: testSiteID
+ in: path
+ required: true
+ schema:
+ type: integer
+ description: Test Site ID
+ responses:
+ '200':
+ description: List of test mappings for the test site
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ message:
+ type: string
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/TestMap'
+ /api/test/testmap/by-host/{hostType}/{hostID}:
+ get:
+ tags:
+ - Tests
+ summary: Get test mappings by host
+ security:
+ - bearerAuth: []
+ parameters:
+ - name: hostType
+ in: path
+ required: true
+ schema:
+ type: string
+ description: Host type code
+ - name: hostID
+ in: path
+ required: true
+ schema:
+ type: string
+ description: Host identifier
+ responses:
+ '200':
+ description: List of test mappings for the host
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ message:
+ type: string
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/TestMap'
+ /api/test/testmap/by-client/{clientType}/{clientID}:
+ get:
+ tags:
+ - Tests
+ summary: Get test mappings by client
+ security:
+ - bearerAuth: []
+ parameters:
+ - name: clientType
+ in: path
+ required: true
+ schema:
+ type: string
+ description: Client type code
+ - name: clientID
+ in: path
+ required: true
+ schema:
+ type: string
+ description: Client identifier
+ responses:
+ '200':
+ description: List of test mappings for the client
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ message:
+ type: string
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/TestMap'
/api/tests:
get:
tags:
@@ -2674,14 +3215,18 @@ paths:
type: string
enum:
- NMRIC
+ - RANGE
+ - TEXT
- VSET
+ - NORES
RefType:
type: string
enum:
- - NMRC
- - TEXT
+ - RANGE
- THOLD
- VSET
+ - TEXT
+ - NOREF
VSet:
type: integer
ReqQty:
@@ -2794,14 +3339,18 @@ paths:
type: string
enum:
- NMRIC
+ - RANGE
+ - TEXT
- VSET
+ - NORES
RefType:
type: string
enum:
- - NMRC
- - TEXT
+ - RANGE
- THOLD
- VSET
+ - TEXT
+ - NOREF
VSet:
type: integer
ReqQty:
@@ -2955,7 +3504,7 @@ paths:
tags:
- ValueSets
summary: List lib value sets
- description: List all library/system value sets from JSON files with item counts. Returns an object where keys are value set names and values are item counts.
+ description: List all library/system value sets from JSON files with item counts. Returns an array of objects with value, label, and count properties.
security:
- bearerAuth: []
parameters:
@@ -2963,7 +3512,7 @@ paths:
in: query
schema:
type: string
- description: Optional search term to filter value set names
+ description: Optional search term to filter value set names or labels
responses:
'200':
description: List of lib value sets with item counts
@@ -2976,14 +3525,19 @@ paths:
type: string
example: success
data:
- type: object
- additionalProperties:
- type: integer
- description: Number of items in each value set
+ type: array
+ items:
+ $ref: '#/components/schemas/ValueSetListItem'
example:
- sex: 3
- marital_status: 6
- order_status: 6
+ - value: sex
+ label: Sex
+ count: 3
+ - value: marital_status
+ label: Marital Status
+ count: 6
+ - value: order_status
+ label: Order Status
+ count: 6
/api/valueset/{key}:
get:
tags:
@@ -4139,22 +4693,46 @@ components:
type: string
enum:
- NMRIC
+ - RANGE
+ - TEXT
- VSET
+ - NORES
description: |
- NMRIC: Numeric result
- VSET: Value set result
+ Result type determines the format of test results:
+ - NMRIC: Single numeric value
+ - RANGE: Numeric range (min-max)
+ - TEXT: Free text result
+ - VSET: Value set/enum result
+ - NORES: No result (for GROUP and TITLE types)
+
+ TestType to ResultType mapping:
+ - TEST: NMRIC | RANGE | TEXT | VSET
+ - PARAM: NMRIC | RANGE | TEXT | VSET
+ - CALC: NMRIC (calculated result is always numeric)
+ - GROUP: NORES (no result, container only)
+ - TITLE: NORES (no result, header only)
RefType:
type: string
enum:
- - NMRC
- - TEXT
+ - RANGE
- THOLD
- VSET
+ - TEXT
+ - NOREF
description: |
- NMRC: Numeric reference range
- TEXT: Text reference
- THOLD: Threshold reference
- VSET: Value set reference
+ Reference type determines which reference range table to use:
+ - RANGE: Numeric reference range
+ - THOLD: Threshold/panic range
+ - VSET: Value set reference
+ - TEXT: Free text reference
+ - NOREF: No reference (for NORES result type)
+
+ ResultType to RefType mapping:
+ - NMRIC: RANGE | THOLD → refnum table
+ - RANGE: RANGE | THOLD → refnum table
+ - VSET: VSET → reftxt table
+ - TEXT: TEXT → reftxt table
+ - NORES: NOREF → (no reference table)
VSet:
type: integer
description: Value set ID for VSET result type
@@ -4530,9 +5108,6 @@ components:
HostID:
type: string
description: Host identifier
- HostDataSource:
- type: string
- description: Host data source
HostTestCode:
type: string
description: Test code in host system
@@ -4545,9 +5120,6 @@ components:
ClientID:
type: string
description: Client identifier
- ClientDataSource:
- type: string
- description: Client data source
ConDefID:
type: integer
description: Connection definition ID
@@ -4812,6 +5384,55 @@ components:
type: string
format: date-time
nullable: true
+ EquipmentList:
+ type: object
+ properties:
+ EID:
+ type: integer
+ description: Equipment ID (auto-increment)
+ IEID:
+ type: string
+ maxLength: 50
+ description: Internal Equipment ID
+ DepartmentID:
+ type: integer
+ description: Reference to department
+ InstrumentID:
+ type: string
+ maxLength: 150
+ description: Instrument identifier
+ InstrumentName:
+ type: string
+ maxLength: 150
+ description: Instrument display name
+ WorkstationID:
+ type: integer
+ description: Reference to workstation
+ Enable:
+ type: integer
+ enum:
+ - 0
+ - 1
+ description: Equipment status (0=disabled, 1=enabled)
+ EquipmentRole:
+ type: string
+ maxLength: 1
+ description: Equipment role code
+ CreateDate:
+ type: string
+ format: date-time
+ description: Creation timestamp
+ EndDate:
+ type: string
+ format: date-time
+ nullable: true
+ description: Deletion timestamp (soft delete)
+ DepartmentName:
+ type: string
+ description: Joined department name
+ WorkstationName:
+ type: string
+ description: Joined workstation name
Contact:
type: object
properties:
@@ -4864,3 +5485,16 @@ components:
type: string
format: date-time
description: Occupation display text
+ ValueSetListItem:
+ type: object
+ description: Library/system value set summary (from JSON files)
+ properties:
+ value:
+ type: string
+ description: The value set key/name
+ label:
+ type: string
+ description: The display name/label
+ count:
+ type: integer
+ description: Number of items in this value set
diff --git a/src/lib/api/equipment.js b/src/lib/api/equipment.js
new file mode 100644
index 0000000..f5ac9b8
--- /dev/null
+++ b/src/lib/api/equipment.js
@@ -0,0 +1,86 @@
+import { get, post, patch, del } from './client.js';
+
+/**
+ * Fetch list of equipment with optional filters
+ * @param {Object} params - Filter parameters
+ * @param {string} [params.IEID] - Filter by IEID
+ * @param {string} [params.InstrumentName] - Filter by instrument name
+ * @param {number} [params.DepartmentID] - Filter by department ID
+ * @param {number} [params.WorkstationID] - Filter by workstation ID
+ * @param {number} [params.Enable] - Filter by enable status (0 or 1)
+ * @returns {Promise