Merge branch 'dev' of https://github.com/dikstub-rssa/simrs-fe into fe-specialist-intern-35
This commit is contained in:
@@ -0,0 +1,30 @@
|
|||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# Default settings for all files
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
# For Markdown files, don't trim trailing whitespace (karena kadang dipakai untuk line break)
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
# For JSON, YAML, and config files
|
||||||
|
[*.{json,yml,yaml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
# For JS, TS, Vue files
|
||||||
|
[*.{js,ts,vue}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
# For CSS, SCSS, PostCSS
|
||||||
|
[*.{css,scss,pcss}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
API_ORIGIN=
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"useTabs": false,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"printWidth": 120,
|
||||||
|
"semi": false,
|
||||||
|
"plugins": ["prettier-plugin-tailwindcss"]
|
||||||
|
}
|
||||||
Vendored
+15
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "chrome",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch Chrome against localhost",
|
||||||
|
"url": "http://localhost:3000",
|
||||||
|
"webRoot": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# Nuxt Minimal Starter
|
||||||
|
|
||||||
|
Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Make sure to install dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm install
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn install
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development Server
|
||||||
|
|
||||||
|
Start the development server on `http://localhost:3000`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm dev
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn dev
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production
|
||||||
|
|
||||||
|
Build the application for production:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm build
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn build
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
|
||||||
|
Locally preview production build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run preview
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm preview
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn preview
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run preview
|
||||||
|
```
|
||||||
|
|
||||||
|
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
||||||
@@ -2,4 +2,111 @@
|
|||||||
|
|
||||||
RSSA - Front End
|
RSSA - Front End
|
||||||
|
|
||||||
If you see this, the development is still not merged yet. Please check another branch.
|
> [!IMPORTANT]
|
||||||
|
> Read this following instructions before doing your job
|
||||||
|
|
||||||
|
## Framework Guide
|
||||||
|
|
||||||
|
- [Vue Style Guide](https://vuejs.org/style-guide)
|
||||||
|
- [Nuxt Style Guide](https://nuxt.com/docs/4.x/guide)
|
||||||
|
- [Shadcn Vue @radix-ui](https://radix.shadcn-vue.com/)
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
- `nuxt.config.ts`<br />Nuxt configuration file
|
||||||
|
- `.env`<br />Some environment variables
|
||||||
|
|
||||||
|
## Directory Structure for `app/`
|
||||||
|
|
||||||
|
- `app.vue`: Main layout
|
||||||
|
- `components` : Contains all reusable UI components.
|
||||||
|
- `components/content` : Entry point for business logic and workflows. Pages or routes call these content components to handle API requests and process application logic
|
||||||
|
- `components/app` : View-layer components that manage and present data. These are used within `content/` to render or handle specific parts of the UI, and return results back to the content
|
||||||
|
- `components/pub` : Public/shared components used across different parts of the app.
|
||||||
|
- `composables` : Contains reusable logic and utility functions (e.g. composables, hooks)..
|
||||||
|
- `layouts` : Reusable UI layout patterns used across pages.
|
||||||
|
- `models` : Contains data definitions or interfaces.
|
||||||
|
- `schemas` : Contains JSON schemas used for validation.
|
||||||
|
- `services` : Contains reusable API calls and business logic.
|
||||||
|
|
||||||
|
|
||||||
|
## Directory Structure for `app/pages`
|
||||||
|
|
||||||
|
- `pages/auth` : Authentication related pages.
|
||||||
|
- `pages/(features)` : Grouped feature modules that reflect specific business content or domains.
|
||||||
|
|
||||||
|
## Directory Structure for `server/`
|
||||||
|
|
||||||
|
- `server/api` : API or proxy requests
|
||||||
|
|
||||||
|
## Workflows
|
||||||
|
|
||||||
|
The basic development workflow follows these steps:
|
||||||
|
|
||||||
|
### Define Your Data in `models/`
|
||||||
|
|
||||||
|
- Create data definitions or interfaces.
|
||||||
|
- These should represent the structure of the data used across your app.
|
||||||
|
|
||||||
|
### Build UI Components in `components/app`
|
||||||
|
|
||||||
|
- Create reusable UI and app specific components.
|
||||||
|
- Keep components pure, avoid making HTTP requests directly within them.
|
||||||
|
- They receive data via props and emit events upward.
|
||||||
|
|
||||||
|
### Business Logic in `components/content`
|
||||||
|
|
||||||
|
- This layer connects the UI with the logic (API calls, validations, navigation).
|
||||||
|
- It composes components from `components/app/`, `components/pub/`, and other content.
|
||||||
|
- Also responsible for managing state, side effects, and interactions.
|
||||||
|
|
||||||
|
### Create Pages in `pages/`
|
||||||
|
|
||||||
|
- Define permissions and guards for each page.
|
||||||
|
- Pages load the appropriate content from `components/content/`.
|
||||||
|
- They do not contain UI or logic directly, just route level layout or guards.
|
||||||
|
|
||||||
|
### Validation
|
||||||
|
|
||||||
|
- UI level validation in `components/app`. help users avoid mistakes before submitting.
|
||||||
|
- Lightweight/instant validation related to UX.
|
||||||
|
- Basic formatting (email regex, numeric-only, password length).
|
||||||
|
- Showing error messages directly under the field.
|
||||||
|
|
||||||
|
- Business level validation in `components/flow`. cannot rely only on the UI, since it often requires server-side checks or rules that may change.
|
||||||
|
- More complex validation rules tied to business logic.
|
||||||
|
|
||||||
|
## Code Conventions
|
||||||
|
|
||||||
|
- Under the script setup block, putting things in group with the following order:
|
||||||
|
- Imports → all dependencies, sorted by external, alias (~), and relative imports.
|
||||||
|
- Props & Emits → clearly define component inputs & outputs.
|
||||||
|
- State & Computed → all ref, reactive, and computed variables grouped together.
|
||||||
|
- Lifecycle Hooks → grouped by mounting → updating → unmounting order.
|
||||||
|
- Functions → async first (fetching, API calls), then utility & event handlers.
|
||||||
|
- Watchers → if needed, put them at the bottom.
|
||||||
|
- Template → keep clean and minimal logic, use methods/computed instead of inline JS.
|
||||||
|
- Declaration Naming
|
||||||
|
- Uses PascalCase for `type` naming
|
||||||
|
- Uses camelCase for `variable` and `const` naming
|
||||||
|
- Underscore can be used to indicates that a variable has derived from an attribute of an object<br />
|
||||||
|
for example: `person_name` indicates it is an attribute `name` from object `person`
|
||||||
|
- Looping
|
||||||
|
- Uses `i`, `j`, `k` as variable for `for` looping index
|
||||||
|
- Uses `item` as object instantition for `forEach` loop callback
|
||||||
|
- Uses `item` as object instantition for `v-for` loop callback in the template
|
||||||
|
|
||||||
|
## Git Workflows
|
||||||
|
|
||||||
|
The basic git workflow follows these steps:
|
||||||
|
|
||||||
|
1. Create a new branch on `dev`
|
||||||
|
- branch name should be `feat/<feature-name>` or `fix/<bug-name>`
|
||||||
|
2. Make your changes
|
||||||
|
3. Commit your changes
|
||||||
|
- commit msg format: `[type]: [description]`
|
||||||
|
- `type` can be `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`
|
||||||
|
- `description` should be a brief description of the changes
|
||||||
|
- Example: `feat: add new feature`
|
||||||
|
4. Push your changes to `dev`
|
||||||
|
5. Create a pull request from `dev` to `main`
|
||||||
|
|||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ConfigProvider } from 'radix-vue'
|
||||||
|
|
||||||
|
const useIdFunction = () => useId()
|
||||||
|
|
||||||
|
const textDirection = useTextDirection({ initialValue: 'ltr' })
|
||||||
|
const dir = computed(() => (textDirection.value === 'rtl' ? 'rtl' : 'ltr'))
|
||||||
|
|
||||||
|
useHead({
|
||||||
|
// as a string,
|
||||||
|
// where `%s` is replaced with the title
|
||||||
|
titleTemplate: '%s - RSSA',
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ConfigProvider :use-id="useIdFunction" :dir="dir">
|
||||||
|
<div vaul-drawer-wrapper class="relative">
|
||||||
|
<NuxtLayout>
|
||||||
|
<NuxtPage />
|
||||||
|
</NuxtLayout>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Toaster />
|
||||||
|
</ConfigProvider>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,340 @@
|
|||||||
|
/* SIMRS RSSA Design System - Pure CSS (No Tailwind) */
|
||||||
|
|
||||||
|
/* CSS Variables */
|
||||||
|
:root {
|
||||||
|
/* Medical Theme Colors */
|
||||||
|
--background: 210 20% 98%;
|
||||||
|
--foreground: 210 20% 15%;
|
||||||
|
--card: 0 0% 100%;
|
||||||
|
--card-foreground: 210 20% 15%;
|
||||||
|
--popover: 0 0% 100%;
|
||||||
|
--popover-foreground: 210 20% 15%;
|
||||||
|
|
||||||
|
/* Primary - Medical Green */
|
||||||
|
--primary: 150 75% 35%;
|
||||||
|
--primary-foreground: 0 0% 100%;
|
||||||
|
--primary-hover: 150 75% 40%;
|
||||||
|
|
||||||
|
/* Secondary - Clean Blue */
|
||||||
|
--secondary: 210 50% 96%;
|
||||||
|
--secondary-foreground: 210 20% 20%;
|
||||||
|
--muted: 210 25% 95%;
|
||||||
|
--muted-foreground: 210 15% 50%;
|
||||||
|
|
||||||
|
/* Accent - Neutral Gray */
|
||||||
|
--accent: 210 40% 96%;
|
||||||
|
--accent-foreground: 222.2 84% 4.9%;
|
||||||
|
--destructive: 0 75% 55%;
|
||||||
|
--destructive-foreground: 0 0% 100%;
|
||||||
|
--border: 210 20% 88%;
|
||||||
|
--input: 210 20% 95%;
|
||||||
|
--ring: 150 75% 35%;
|
||||||
|
|
||||||
|
/* Medical Status Colors */
|
||||||
|
--success: 150 75% 40%;
|
||||||
|
--success-foreground: 0 0% 100%;
|
||||||
|
--warning: 45 95% 60%;
|
||||||
|
--warning-foreground: 210 20% 15%;
|
||||||
|
--info: 210 100% 50%;
|
||||||
|
--info-foreground: 0 0% 100%;
|
||||||
|
|
||||||
|
/* Gradients */
|
||||||
|
--gradient-primary: linear-gradient(135deg, hsl(150 75% 35%), hsl(150 75% 45%));
|
||||||
|
--gradient-medical: linear-gradient(135deg, hsl(150 75% 35%), hsl(210 100% 50%));
|
||||||
|
--gradient-subtle: linear-gradient(180deg, hsl(210 20% 98%), hsl(210 25% 95%));
|
||||||
|
|
||||||
|
/* Shadows */
|
||||||
|
--shadow-medical: 0 4px 20px -4px hsl(150 75% 35% / 0.15);
|
||||||
|
--shadow-card: 0 2px 10px -2px hsl(210 20% 15% / 0.1);
|
||||||
|
--shadow-glow: 0 0 30px hsl(150 75% 35% / 0.2);
|
||||||
|
|
||||||
|
/* Transitions */
|
||||||
|
--transition-smooth: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
--transition-fast: all 0.15s ease-out;
|
||||||
|
|
||||||
|
/* Border Radius */
|
||||||
|
--radius: 0.5rem;
|
||||||
|
--radius-lg: var(--radius);
|
||||||
|
--radius-md: calc(var(--radius) - 2px);
|
||||||
|
--radius-sm: calc(var(--radius) - 4px);
|
||||||
|
|
||||||
|
/* Sidebar */
|
||||||
|
--sidebar-background: 0 0% 98%;
|
||||||
|
--sidebar-foreground: 240 5.3% 26.1%;
|
||||||
|
--sidebar-primary: 240 5.9% 10%;
|
||||||
|
--sidebar-primary-foreground: 0 0% 98%;
|
||||||
|
--sidebar-accent: 240 4.8% 95.9%;
|
||||||
|
--sidebar-accent-foreground: 240 5.9% 10%;
|
||||||
|
--sidebar-border: 220 13% 91%;
|
||||||
|
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||||
|
/* .dark { */
|
||||||
|
/* --background: 210 25% 8%; */
|
||||||
|
/* --foreground: 210 20% 95%; */
|
||||||
|
/* --card: 210 25% 10%; */
|
||||||
|
/* --card-foreground: 210 20% 95%; */
|
||||||
|
/* --popover: 210 25% 10%; */
|
||||||
|
/* --popover-foreground: 210 20% 95%; */
|
||||||
|
/* --primary: 150 75% 45%; */
|
||||||
|
/* --primary-foreground: 0 0% 100%; */
|
||||||
|
/* --primary-hover: 150 75% 50%; */
|
||||||
|
/* --secondary: 210 25% 15%; */
|
||||||
|
/* --secondary-foreground: 210 20% 90%; */
|
||||||
|
/* --muted: 210 25% 15%; */
|
||||||
|
/* --muted-foreground: 210 15% 65%; */
|
||||||
|
/* --accent: 210 100% 55%; */
|
||||||
|
/* --accent-foreground: 0 0% 100%; */
|
||||||
|
/* --destructive: 0 75% 60%; */
|
||||||
|
/* --destructive-foreground: 0 0% 100%; */
|
||||||
|
/* --border: 210 25% 20%; */
|
||||||
|
/* --input: 210 25% 15%; */
|
||||||
|
/* --ring: 150 75% 45%; */
|
||||||
|
/* --success: 150 75% 50%; */
|
||||||
|
/* --warning: 45 95% 65%; */
|
||||||
|
/* --info: 210 100% 60%; */
|
||||||
|
/* --gradient-primary: linear-gradient(135deg, hsl(150 75% 45%), hsl(150 75% 55%)); */
|
||||||
|
/* --gradient-medical: linear-gradient(135deg, hsl(150 75% 45%), hsl(210 100% 55%)); */
|
||||||
|
/* --gradient-subtle: linear-gradient(180deg, hsl(210 25% 8%), hsl(210 25% 12%)); */
|
||||||
|
/* --sidebar-background: 240 5.9% 10%; */
|
||||||
|
/* --sidebar-foreground: 240 4.8% 95.9%; */
|
||||||
|
/* --sidebar-primary: 224.3 76.3% 48%; */
|
||||||
|
/* --sidebar-primary-foreground: 0 0% 100%; */
|
||||||
|
/* --sidebar-accent: 240 3.7% 15.9%; */
|
||||||
|
/* --sidebar-accent-foreground: 240 4.8% 95.9%; */
|
||||||
|
/* --sidebar-border: 240 3.7% 15.9%; */
|
||||||
|
/* --sidebar-ring: 217.2 91.2% 59.8%; */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keyframes for Animations */
|
||||||
|
@keyframes accordion-down {
|
||||||
|
from {
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
height: var(--radix-accordion-content-height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes accordion-up {
|
||||||
|
from {
|
||||||
|
height: var(--radix-accordion-content-height);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(10px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideUp {
|
||||||
|
0% {
|
||||||
|
transform: translateY(100%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulseMedical {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
box-shadow: 0 0 0 0 hsl(var(--primary) / 0.4);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
box-shadow: 0 0 0 10px hsl(var(--primary) / 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Base Styles */
|
||||||
|
* {
|
||||||
|
border-color: hsl(var(--border));
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: hsl(var(--background));
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
line-height: 1.5;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Container */
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1400px) {
|
||||||
|
.container {
|
||||||
|
max-width: 1400px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Color Classes */
|
||||||
|
.bg-background {
|
||||||
|
background-color: hsl(var(--background));
|
||||||
|
}
|
||||||
|
.bg-foreground {
|
||||||
|
background-color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
.bg-card {
|
||||||
|
background-color: hsl(var(--card));
|
||||||
|
}
|
||||||
|
.bg-primary {
|
||||||
|
background-color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
.bg-secondary {
|
||||||
|
background-color: hsl(var(--secondary));
|
||||||
|
}
|
||||||
|
.bg-accent {
|
||||||
|
background-color: hsl(var(--accent));
|
||||||
|
}
|
||||||
|
.bg-destructive {
|
||||||
|
background-color: hsl(var(--destructive));
|
||||||
|
}
|
||||||
|
.bg-muted {
|
||||||
|
background-color: hsl(var(--muted));
|
||||||
|
}
|
||||||
|
.bg-success {
|
||||||
|
background-color: hsl(var(--success));
|
||||||
|
}
|
||||||
|
.bg-warning {
|
||||||
|
background-color: hsl(var(--warning));
|
||||||
|
}
|
||||||
|
.bg-info {
|
||||||
|
background-color: hsl(var(--info));
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-background {
|
||||||
|
color: hsl(var(--background));
|
||||||
|
}
|
||||||
|
.text-foreground {
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
}
|
||||||
|
.text-card {
|
||||||
|
color: hsl(var(--card));
|
||||||
|
}
|
||||||
|
.text-primary {
|
||||||
|
color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
.text-secondary {
|
||||||
|
color: hsl(var(--secondary));
|
||||||
|
}
|
||||||
|
.text-accent {
|
||||||
|
color: hsl(var(--accent));
|
||||||
|
}
|
||||||
|
.text-destructive {
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
}
|
||||||
|
.text-muted {
|
||||||
|
color: hsl(var(--muted));
|
||||||
|
}
|
||||||
|
.text-success {
|
||||||
|
color: hsl(var(--success));
|
||||||
|
}
|
||||||
|
.text-warning {
|
||||||
|
color: hsl(var(--warning));
|
||||||
|
}
|
||||||
|
.text-info {
|
||||||
|
color: hsl(var(--info));
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-primary-foreground {
|
||||||
|
color: hsl(var(--primary-foreground));
|
||||||
|
}
|
||||||
|
.text-secondary-foreground {
|
||||||
|
color: hsl(var(--secondary-foreground));
|
||||||
|
}
|
||||||
|
.text-accent-foreground {
|
||||||
|
color: hsl(var(--accent-foreground));
|
||||||
|
}
|
||||||
|
.text-destructive-foreground {
|
||||||
|
color: hsl(var(--destructive-foreground));
|
||||||
|
}
|
||||||
|
.text-muted-foreground {
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
}
|
||||||
|
.text-success-foreground {
|
||||||
|
color: hsl(var(--success-foreground));
|
||||||
|
}
|
||||||
|
.text-warning-foreground {
|
||||||
|
color: hsl(var(--warning-foreground));
|
||||||
|
}
|
||||||
|
.text-info-foreground {
|
||||||
|
color: hsl(var(--info-foreground));
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-primary {
|
||||||
|
border-color: hsl(var(--primary));
|
||||||
|
}
|
||||||
|
.border-secondary {
|
||||||
|
border-color: hsl(var(--secondary));
|
||||||
|
}
|
||||||
|
.border-accent {
|
||||||
|
border-color: hsl(var(--accent));
|
||||||
|
}
|
||||||
|
.border-destructive {
|
||||||
|
border-color: hsl(var(--destructive));
|
||||||
|
}
|
||||||
|
.border-input {
|
||||||
|
border-color: hsl(var(--input));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sidebar Colors */
|
||||||
|
.bg-sidebar {
|
||||||
|
background-color: hsl(var(--sidebar-background));
|
||||||
|
}
|
||||||
|
.text-sidebar {
|
||||||
|
color: hsl(var(--sidebar-foreground));
|
||||||
|
}
|
||||||
|
.bg-sidebar-primary {
|
||||||
|
background-color: hsl(var(--sidebar-primary));
|
||||||
|
}
|
||||||
|
.text-sidebar-primary {
|
||||||
|
color: hsl(var(--sidebar-primary));
|
||||||
|
}
|
||||||
|
.bg-sidebar-accent {
|
||||||
|
background-color: hsl(var(--sidebar-accent));
|
||||||
|
}
|
||||||
|
.text-sidebar-accent {
|
||||||
|
color: hsl(var(--sidebar-accent));
|
||||||
|
}
|
||||||
|
.border-sidebar {
|
||||||
|
border-color: hsl(var(--sidebar-border));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Background Images */
|
||||||
|
.bg-gradient-medical {
|
||||||
|
background-image: var(--gradient-medical);
|
||||||
|
}
|
||||||
|
.bg-gradient-primary {
|
||||||
|
background-image: var(--gradient-primary);
|
||||||
|
}
|
||||||
|
.bg-gradient-subtle {
|
||||||
|
background-image: var(--gradient-subtle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Border Radius */
|
||||||
|
.rounded-sm {
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Form Error Styling */
|
||||||
|
.field-error-info {
|
||||||
|
@apply text-xs ml-1;
|
||||||
|
color: hsl(var(--destructive));
|
||||||
|
/* font-size: 0.875rem; */
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .rounded-md { border-radius: var */
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { z } from 'zod'
|
||||||
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
import { Loader2 } from 'lucide-vue-next'
|
||||||
|
import { useForm } from 'vee-validate'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
schema: z.ZodSchema<any>
|
||||||
|
isLoading: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
submit: [data: any]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { handleSubmit, defineField, errors, meta } = useForm({
|
||||||
|
validationSchema: toTypedSchema(props.schema),
|
||||||
|
initialValues: {
|
||||||
|
name: '',
|
||||||
|
password: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const [name, nameAttrs] = defineField('name')
|
||||||
|
const [password, passwordAttrs] = defineField('password')
|
||||||
|
|
||||||
|
const onSubmit = handleSubmit(async (values) => {
|
||||||
|
try {
|
||||||
|
await emit('submit', values)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Submission failed:', error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form class="grid gap-6" @submit="onSubmit">
|
||||||
|
<div class="grid gap-2">
|
||||||
|
<Label for="name">Username</Label>
|
||||||
|
<Input
|
||||||
|
id="name"
|
||||||
|
v-model="name"
|
||||||
|
v-bind="nameAttrs"
|
||||||
|
:disabled="isLoading"
|
||||||
|
:class="{ 'border-red-500': errors.name }"
|
||||||
|
/>
|
||||||
|
<span v-if="errors.name" class="text-sm text-red-500">
|
||||||
|
{{ errors.name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid gap-2">
|
||||||
|
<Label for="password">Password</Label>
|
||||||
|
<Input
|
||||||
|
id="password"
|
||||||
|
v-model="password"
|
||||||
|
v-bind="passwordAttrs"
|
||||||
|
type="password"
|
||||||
|
:disabled="isLoading"
|
||||||
|
:class="{ 'border-red-500': errors.password }"
|
||||||
|
/>
|
||||||
|
<span v-if="errors.password" class="text-sm text-red-500">
|
||||||
|
{{ errors.password }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button type="submit" class="w-full" :disabled="isLoading || !meta.valid">
|
||||||
|
<Loader2 v-if="isLoading" class="mr-2 h-4 w-4 animate-spin" />
|
||||||
|
Login
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { FormErrors } from '~/types/error'
|
||||||
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
import Combobox from '~/components/pub/custom-ui/form/combobox.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
|
||||||
|
interface DivisionFormData {
|
||||||
|
name: string
|
||||||
|
code: string
|
||||||
|
parentId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
division: {
|
||||||
|
msg: {
|
||||||
|
placeholder: string
|
||||||
|
search: string
|
||||||
|
empty: string
|
||||||
|
}
|
||||||
|
items: {
|
||||||
|
value: string
|
||||||
|
label: string
|
||||||
|
code: string
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
schema: any
|
||||||
|
initialValues?: Partial<DivisionFormData>
|
||||||
|
errors?: FormErrors
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'submit': [values: DivisionFormData, resetForm: () => void]
|
||||||
|
'cancel': [resetForm: () => void]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const formSchema = toTypedSchema(props.schema)
|
||||||
|
|
||||||
|
// Form submission handler
|
||||||
|
function onSubmitForm(values: any, { resetForm }: { resetForm: () => void }) {
|
||||||
|
const formData: DivisionFormData = {
|
||||||
|
name: values.name || '',
|
||||||
|
code: values.code || '',
|
||||||
|
parentId: values.parentId || '',
|
||||||
|
}
|
||||||
|
emit('submit', formData, resetForm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Form cancel handler
|
||||||
|
function onCancelForm({ resetForm }: { resetForm: () => void }) {
|
||||||
|
emit('cancel', resetForm)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Form
|
||||||
|
v-slot="{ handleSubmit, resetForm }" as="" keep-values :validation-schema="formSchema"
|
||||||
|
:initial-values="initialValues"
|
||||||
|
>
|
||||||
|
<form id="entry-form" @submit="handleSubmit($event, (values) => onSubmitForm(values, { resetForm }))">
|
||||||
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="name">Nama</Label>
|
||||||
|
<Field id="name" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="name">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="name" type="text" placeholder="Masukkan nama divisi" autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="code">Kode</Label>
|
||||||
|
<Field id="code" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="code">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input id="code" type="text" placeholder="Masukkan kode divisi" autocomplete="off" v-bind="componentField" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label label-for="parentId">Kelompok</Label>
|
||||||
|
<Field id="parentId" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="parentId">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Combobox
|
||||||
|
id="parentId" v-bind="componentField" :items="props.division.items"
|
||||||
|
:placeholder="props.division.msg.placeholder" :search-placeholder="props.division.msg.search"
|
||||||
|
:empty-message="props.division.msg.empty"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end gap-2 mt-4">
|
||||||
|
<Button type="button" variant="outline" @click="onCancelForm({ resetForm })">
|
||||||
|
Batal
|
||||||
|
</Button>
|
||||||
|
<Button type="submit">
|
||||||
|
Simpan
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import type {
|
||||||
|
Col,
|
||||||
|
KeyLabel,
|
||||||
|
RecComponent,
|
||||||
|
RecStrFuncComponent,
|
||||||
|
RecStrFuncUnknown,
|
||||||
|
Th,
|
||||||
|
} from '~/components/pub/custom-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
type SmallDetailDto = any
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-ud.vue'))
|
||||||
|
|
||||||
|
export const cols: Col[] = [
|
||||||
|
{ width: 100 },
|
||||||
|
{ },
|
||||||
|
{ },
|
||||||
|
{ },
|
||||||
|
{ width: 50 },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const header: Th[][] = [
|
||||||
|
[
|
||||||
|
{ label: 'Id' },
|
||||||
|
{ label: 'Nama' },
|
||||||
|
{ label: 'Kode' },
|
||||||
|
{ label: 'Kelompok' },
|
||||||
|
{ label: '' },
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
export const keys = [
|
||||||
|
'id',
|
||||||
|
'firstName',
|
||||||
|
'cellphone',
|
||||||
|
'birth_place',
|
||||||
|
'action',
|
||||||
|
]
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {
|
||||||
|
name: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||||
|
},
|
||||||
|
identity_number: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||||
|
return '(TANPA NIK)'
|
||||||
|
}
|
||||||
|
return recX.identity_number
|
||||||
|
},
|
||||||
|
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||||
|
},
|
||||||
|
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
props: {
|
||||||
|
size: 'sm',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {
|
||||||
|
patient_address(_rec) {
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { PaginationMeta } from '~/components/pub/custom-ui/pagination/pagination.type'
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
data: any[]
|
||||||
|
paginationMeta?: PaginationMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<Props>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
pageChange: [page: number]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
function handlePageChange(page: number) {
|
||||||
|
emit('pageChange', page)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<PubBaseDataTable
|
||||||
|
:rows="data" :cols="cols" :header="header" :keys="keys" :func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml" :func-component="funcComponent" :skeleton-size="paginationMeta?.pageSize"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<template v-if="paginationMeta">
|
||||||
|
<div v-if="paginationMeta.totalPage > 1">
|
||||||
|
<PubCustomUiPagination :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Block from '~/components/pub/custom-ui/form/block.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: any }>()
|
||||||
|
const emit = defineEmits(['update:modelValue', 'event'])
|
||||||
|
|
||||||
|
const data = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (val) => emit('update:modelValue', val),
|
||||||
|
})
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{ value: 'doctor', label: 'Dokter' },
|
||||||
|
{ value: 'nurse', label: 'Perawat' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="entry-form">
|
||||||
|
<div class="mb-2 border-b border-b-slate-300 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<Block>
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label>No. IHS</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label>No. SIP</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label>Unit</Label>
|
||||||
|
<Field>
|
||||||
|
<Select v-model="data.type" :items="items" placeholder="Pilih jenis" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import type {
|
||||||
|
Col,
|
||||||
|
KeyLabel,
|
||||||
|
RecComponent,
|
||||||
|
RecStrFuncComponent,
|
||||||
|
RecStrFuncUnknown,
|
||||||
|
Th,
|
||||||
|
} from '~/components/pub/custom-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
type SmallDetailDto = any
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue'))
|
||||||
|
const statusBadge = defineAsyncComponent(() => import('./status-badge.vue'))
|
||||||
|
|
||||||
|
const _doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cols: Col[] = [
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 250 },
|
||||||
|
{},
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 100 },
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 100 },
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const header: Th[][] = [
|
||||||
|
[
|
||||||
|
{ label: 'Kode JKN' },
|
||||||
|
{ label: 'Nama' },
|
||||||
|
{ label: 'No KTP' },
|
||||||
|
{ label: 'No SIP' },
|
||||||
|
{ label: 'No IHS' },
|
||||||
|
{ label: 'Telpon' },
|
||||||
|
{ label: 'Fee Ranap' },
|
||||||
|
{ label: 'Fee Rajal' },
|
||||||
|
{ label: 'Status' },
|
||||||
|
{ label: '' },
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
export const keys = [
|
||||||
|
'bpjs_code',
|
||||||
|
'name',
|
||||||
|
'identity_number',
|
||||||
|
'sip_no',
|
||||||
|
'ihs_number',
|
||||||
|
'phone',
|
||||||
|
'inPatient_itemPrice',
|
||||||
|
'outPatient_itemPrice',
|
||||||
|
'status',
|
||||||
|
'action',
|
||||||
|
]
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {
|
||||||
|
name: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||||
|
},
|
||||||
|
identity_number: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||||
|
return '(TANPA NIK)'
|
||||||
|
}
|
||||||
|
return recX.identity_number
|
||||||
|
},
|
||||||
|
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||||
|
},
|
||||||
|
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
status(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: statusBadge,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {
|
||||||
|
patient_address(_rec) {
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
data: any[]
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PubBaseDataTable
|
||||||
|
:rows="data"
|
||||||
|
:cols="cols"
|
||||||
|
:header="header"
|
||||||
|
:keys="keys"
|
||||||
|
:func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml"
|
||||||
|
:func-component="funcComponent"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Badge } from '~/components/pub/ui/badge'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rec: any
|
||||||
|
idx?: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusText = computed(() => {
|
||||||
|
return doctorStatus[props.rec.status_code as keyof typeof doctorStatus]
|
||||||
|
})
|
||||||
|
|
||||||
|
const badgeVariant = computed(() => {
|
||||||
|
return props.rec.status_code === 1 ? 'default' : 'destructive'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<Badge :variant="badgeVariant">
|
||||||
|
{{ statusText }}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Block from '~/components/pub/custom-ui/form/block.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: any; items: any[] }>()
|
||||||
|
const emit = defineEmits(['update:modelValue', 'event'])
|
||||||
|
|
||||||
|
const data = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (val) => emit('update:modelValue', val),
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="entry-form">
|
||||||
|
<div class="mb-5 border-b border-b-slate-300 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<Block>
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label>Nomor Induk Pegawai</Label>
|
||||||
|
<Field>
|
||||||
|
<Input v-model="data.number" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label>Status</Label>
|
||||||
|
<Field>
|
||||||
|
<Select v-model="data.type" :items="items" placeholder="Pilih jenis" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label>Position</Label>
|
||||||
|
<Field>
|
||||||
|
<Select v-model="data.type" :items="items" placeholder="Pilih jenis" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label>Divisi</Label>
|
||||||
|
<Field>
|
||||||
|
<Select v-model="data.type" :items="items" placeholder="Pilih jenis" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
import type {
|
||||||
|
Col,
|
||||||
|
KeyLabel,
|
||||||
|
RecComponent,
|
||||||
|
RecStrFuncComponent,
|
||||||
|
RecStrFuncUnknown,
|
||||||
|
Th,
|
||||||
|
} from '~/components/pub/custom-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
type SmallDetailDto = any
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue'))
|
||||||
|
|
||||||
|
const doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cols: Col[] = [
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 250 },
|
||||||
|
{},
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 100 },
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 50 },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const header: Th[][] = [
|
||||||
|
[
|
||||||
|
{ label: 'Kode JKN' },
|
||||||
|
{ label: 'Nama' },
|
||||||
|
{ label: 'No KTP' },
|
||||||
|
{ label: 'No SIP' },
|
||||||
|
{ label: 'No IHS' },
|
||||||
|
{ label: 'Telpon' },
|
||||||
|
{ label: 'Fee Ranap' },
|
||||||
|
{ label: 'Fee Rajal' },
|
||||||
|
{ label: 'Status' },
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
export const keys = [
|
||||||
|
'bpjs_code',
|
||||||
|
'name',
|
||||||
|
'identity_number',
|
||||||
|
'sip_no',
|
||||||
|
'ihs_number',
|
||||||
|
'phone',
|
||||||
|
'inPatient_itemPrice',
|
||||||
|
'outPatient_itemPrice',
|
||||||
|
'status',
|
||||||
|
'action',
|
||||||
|
]
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {
|
||||||
|
name: (rec: unknown): unknown => {
|
||||||
|
console.log(rec)
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||||
|
},
|
||||||
|
identity_number: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||||
|
return '(TANPA NIK)'
|
||||||
|
}
|
||||||
|
return recX.identity_number
|
||||||
|
},
|
||||||
|
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||||
|
},
|
||||||
|
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||||
|
},
|
||||||
|
status: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return doctorStatus[recX.status_code as keyof typeof doctorStatus]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {
|
||||||
|
patient_address(_rec) {
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
data: any[]
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PubBaseDataTable
|
||||||
|
:rows="data"
|
||||||
|
:cols="cols"
|
||||||
|
:header="header"
|
||||||
|
:keys="keys"
|
||||||
|
:func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml"
|
||||||
|
:func-component="funcComponent"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// types
|
||||||
|
import type z from 'zod'
|
||||||
|
import type { MaterialFormData } from '~/schemas/material'
|
||||||
|
// helpers
|
||||||
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
import { useForm } from 'vee-validate'
|
||||||
|
// components
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
schema: z.ZodSchema<any>
|
||||||
|
uoms: any[]
|
||||||
|
items: any[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const isLoading = ref(false)
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
const emit = defineEmits<{
|
||||||
|
submit: [values: MaterialFormData, resetForm: () => void]
|
||||||
|
cancel: [resetForm: () => void]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { handleSubmit, defineField, errors } = useForm({
|
||||||
|
validationSchema: toTypedSchema(props.schema),
|
||||||
|
initialValues: {
|
||||||
|
code: '',
|
||||||
|
name: '',
|
||||||
|
uom_code: '',
|
||||||
|
item_id: '',
|
||||||
|
stock: 0,
|
||||||
|
} as Partial<MaterialFormData>,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [code, codeAttrs] = defineField('code')
|
||||||
|
const [name, nameAttrs] = defineField('name')
|
||||||
|
const [uom, uomAttrs] = defineField('uom_code')
|
||||||
|
const [item, itemAttrs] = defineField('item_id')
|
||||||
|
const [stock, stockAttrs] = defineField('stock')
|
||||||
|
|
||||||
|
const resetForm = () => {
|
||||||
|
code.value = ''
|
||||||
|
name.value = ''
|
||||||
|
uom.value = ''
|
||||||
|
item.value = ''
|
||||||
|
stock.value = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Form submission handler
|
||||||
|
function onSubmitForm(values: any) {
|
||||||
|
const formData: MaterialFormData = {
|
||||||
|
name: values.name || '',
|
||||||
|
code: values.code || '',
|
||||||
|
uom_code: values.uom_code || '',
|
||||||
|
item_id: values.item_id || '',
|
||||||
|
stock: values.stock || 0,
|
||||||
|
}
|
||||||
|
emit('submit', formData, resetForm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Form cancel handler
|
||||||
|
function onCancelForm() {
|
||||||
|
emit('cancel', resetForm)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form class="grid gap-2" @submit="handleSubmit(onSubmitForm)">
|
||||||
|
<div class="grid gap-2">
|
||||||
|
<label for="code">Kode</label>
|
||||||
|
<Input
|
||||||
|
id="code"
|
||||||
|
v-model="code"
|
||||||
|
v-bind="codeAttrs"
|
||||||
|
:disabled="isLoading"
|
||||||
|
:class="{ 'border-red-500': errors.code }"
|
||||||
|
/>
|
||||||
|
<span v-if="errors.code" class="text-sm text-red-500">
|
||||||
|
{{ errors.code }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="grid gap-2">
|
||||||
|
<label for="name">Nama</label>
|
||||||
|
<Input
|
||||||
|
id="name"
|
||||||
|
v-model="name"
|
||||||
|
v-bind="nameAttrs"
|
||||||
|
:disabled="isLoading"
|
||||||
|
:class="{ 'border-red-500': errors.name }"
|
||||||
|
/>
|
||||||
|
<span v-if="errors.name" class="text-sm text-red-500">
|
||||||
|
{{ errors.name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="grid gap-2">
|
||||||
|
<label for="uom">Satuan</label>
|
||||||
|
<Select
|
||||||
|
id="uom"
|
||||||
|
v-model="uom"
|
||||||
|
icon-name="i-lucide-chevron-down"
|
||||||
|
placeholder="Pilih satuan"
|
||||||
|
v-bind="uomAttrs"
|
||||||
|
:items="uoms"
|
||||||
|
:disabled="isLoading"
|
||||||
|
:class="{ 'border-red-500': errors.uom_code }"
|
||||||
|
/>
|
||||||
|
<span v-if="errors.uom_code" class="text-sm text-red-500">
|
||||||
|
{{ errors.uom_code }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="grid gap-2">
|
||||||
|
<label for="item">Item</label>
|
||||||
|
<Select
|
||||||
|
id="item"
|
||||||
|
v-model="item"
|
||||||
|
icon-name="i-lucide-chevron-down"
|
||||||
|
placeholder="Pilih item"
|
||||||
|
v-bind="itemAttrs"
|
||||||
|
:items="items"
|
||||||
|
:disabled="isLoading"
|
||||||
|
:class="{ 'border-red-500': errors.item_id }"
|
||||||
|
/>
|
||||||
|
<span v-if="errors.item_id" class="text-sm text-red-500">
|
||||||
|
{{ errors.item_id }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="grid gap-2">
|
||||||
|
<label for="stock">Stok</label>
|
||||||
|
<Input
|
||||||
|
id="stock"
|
||||||
|
v-model="stock"
|
||||||
|
type="number"
|
||||||
|
v-bind="stockAttrs"
|
||||||
|
:disabled="isLoading"
|
||||||
|
:class="{ 'border-red-500': errors.stock }"
|
||||||
|
/>
|
||||||
|
<span v-if="errors.stock" class="text-sm text-red-500">
|
||||||
|
{{ errors.stock }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="my-2 flex justify-end gap-2 py-2">
|
||||||
|
<Button variant="secondary" class="w-[120px]" @click="onCancelForm"> Kembali </Button>
|
||||||
|
<Button type="submit" class="w-[120px]">
|
||||||
|
<Loader2 v-if="isLoading" class="mr-2 h-4 w-4 animate-spin" />
|
||||||
|
Simpan
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import type {
|
||||||
|
Col,
|
||||||
|
KeyLabel,
|
||||||
|
RecComponent,
|
||||||
|
RecStrFuncComponent,
|
||||||
|
Th,
|
||||||
|
} from '~/components/pub/custom-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
type SmallDetailDto = any
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue'))
|
||||||
|
|
||||||
|
export const cols: Col[] = [{ width: 100 }, { width: 250 }, { width: 100 }, { width: 100 }, { width: 100 }, { width: 50 }]
|
||||||
|
|
||||||
|
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Stok' }, { label: 'Item' }, { label: 'Satuan' }]]
|
||||||
|
|
||||||
|
export const keys = ['code', 'name', 'stock', 'item_id', 'uom_code', 'action']
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: Record<string, (row: any, ...args: any[]) => any> = {
|
||||||
|
name: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return `${recX.name}`.trim()
|
||||||
|
},
|
||||||
|
item_id: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return recX.item_id
|
||||||
|
},
|
||||||
|
uom_code: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return recX.uom_code
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: Record<string, (row: any, ...args: any[]) => any> = {}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { PaginationMeta } from '~/components/pub/custom-ui/pagination/pagination.type'
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
data: any[]
|
||||||
|
paginationMeta?: PaginationMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<Props>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
pageChange: [page: number]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
function handlePageChange(page: number) {
|
||||||
|
emit('pageChange', page)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<PubBaseDataTable
|
||||||
|
:rows="data"
|
||||||
|
:cols="cols"
|
||||||
|
:header="header"
|
||||||
|
:keys="keys"
|
||||||
|
:func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml"
|
||||||
|
:func-component="funcComponent"
|
||||||
|
/>
|
||||||
|
<template v-if="paginationMeta">
|
||||||
|
<div v-if="paginationMeta.totalPage > 1">
|
||||||
|
<PubCustomUiPagination :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { FormErrors } from '~/types/error'
|
||||||
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
import Select from '~/components/pub/custom-ui/form/select.vue'
|
||||||
|
|
||||||
|
interface InstallationFormData {
|
||||||
|
name: string
|
||||||
|
code: string
|
||||||
|
encounterClassCode: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
installation: {
|
||||||
|
msg: {
|
||||||
|
placeholder: string
|
||||||
|
}
|
||||||
|
items: {
|
||||||
|
value: string
|
||||||
|
label: string
|
||||||
|
code: string
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
schema: any
|
||||||
|
initialValues?: Partial<InstallationFormData>
|
||||||
|
errors?: FormErrors
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'submit': [values: InstallationFormData, resetForm: () => void]
|
||||||
|
'cancel': [resetForm: () => void]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const formSchema = toTypedSchema(props.schema)
|
||||||
|
|
||||||
|
// Form submission handler
|
||||||
|
function onSubmitForm(values: any, { resetForm }: { resetForm: () => void }) {
|
||||||
|
const formData: InstallationFormData = {
|
||||||
|
name: values.name || '',
|
||||||
|
code: values.code || '',
|
||||||
|
encounterClassCode: values.encounterClassCode || '',
|
||||||
|
}
|
||||||
|
emit('submit', formData, resetForm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Form cancel handler
|
||||||
|
function onCancelForm({ resetForm }: { resetForm: () => void }) {
|
||||||
|
emit('cancel', resetForm)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Form
|
||||||
|
v-slot="{ handleSubmit, resetForm }" as="" keep-values :validation-schema="formSchema"
|
||||||
|
:initial-values="initialValues"
|
||||||
|
>
|
||||||
|
<form id="entry-form" @submit="handleSubmit($event, (values) => onSubmitForm(values, { resetForm }))">
|
||||||
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="name">Nama</Label>
|
||||||
|
<Field id="name" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="name">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="name" type="text" placeholder="Masukkan nama instalasi" autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="code">Kode</Label>
|
||||||
|
<Field id="code" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="code">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input id="code" type="text" placeholder="Masukkan kode instalasi" autocomplete="off" v-bind="componentField" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="parentId">Encounter Class</Label>
|
||||||
|
<Field id="encounterClassCode" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="encounterClassCode">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Select
|
||||||
|
v-bind="componentField"
|
||||||
|
:items="installation.items"
|
||||||
|
:placeholder="installation.msg.placeholder"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end gap-2 mt-4">
|
||||||
|
<Button type="button" variant="outline" @click="onCancelForm({ resetForm })">
|
||||||
|
Batal
|
||||||
|
</Button>
|
||||||
|
<Button type="submit">
|
||||||
|
Simpan
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import type {
|
||||||
|
Col,
|
||||||
|
KeyLabel,
|
||||||
|
RecComponent,
|
||||||
|
RecStrFuncComponent,
|
||||||
|
RecStrFuncUnknown,
|
||||||
|
Th,
|
||||||
|
} from '~/components/pub/custom-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
type SmallDetailDto = any
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-ud.vue'))
|
||||||
|
|
||||||
|
export const cols: Col[] = [{ width: 100 }, {}, {}, {}, { width: 50 }]
|
||||||
|
|
||||||
|
export const header: Th[][] = [
|
||||||
|
[{ label: 'Id' }, { label: 'Nama' }, { label: 'Kode' }, { label: 'Encounter Class' }, { label: '' }],
|
||||||
|
]
|
||||||
|
|
||||||
|
export const keys = ['id', 'name', 'cellphone', 'religion_code', 'action']
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {
|
||||||
|
name: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return `${recX.firstName} ${recX.lastName || ''}`.trim()
|
||||||
|
},
|
||||||
|
identity_number: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||||
|
return '(TANPA NIK)'
|
||||||
|
}
|
||||||
|
return recX.identity_number
|
||||||
|
},
|
||||||
|
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||||
|
},
|
||||||
|
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
props: {
|
||||||
|
size: 'sm',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {
|
||||||
|
patient_address(_rec) {
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { PaginationMeta } from '~/components/pub/custom-ui/pagination/pagination.type'
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
data: any[]
|
||||||
|
paginationMeta?: PaginationMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<Props>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
pageChange: [page: number]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
function handlePageChange(page: number) {
|
||||||
|
emit('pageChange', page)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<PubBaseDataTable
|
||||||
|
:rows="data" :cols="cols" :header="header" :keys="keys" :func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml" :func-component="funcComponent" :skeleton-size="paginationMeta?.pageSize"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Data info and pagination -->
|
||||||
|
<template v-if="paginationMeta">
|
||||||
|
<div v-if="paginationMeta.totalPage > 1">
|
||||||
|
<PubCustomUiPagination :pagination-meta="paginationMeta" @page-change="handlePageChange" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Block from '~/components/pub/custom-ui/form/block.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: any }>()
|
||||||
|
const emit = defineEmits(['update:modelValue', 'event'])
|
||||||
|
|
||||||
|
const data = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (val) => emit('update:modelValue', val),
|
||||||
|
})
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{ value: '1', label: 'item 1' },
|
||||||
|
{ value: '2', label: 'item 2' },
|
||||||
|
{ value: '3', label: 'item 3' },
|
||||||
|
{ value: '4', label: 'item 4' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="entry-form">
|
||||||
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<Block>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label>Items</Label>
|
||||||
|
<Field>
|
||||||
|
<Select :items="items" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label>Perusahaan Insuransi</Label>
|
||||||
|
<Field>
|
||||||
|
<Select :items="items" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label>Harga</Label>
|
||||||
|
<Field>
|
||||||
|
<Input v-model="data.price" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import type {
|
||||||
|
Col,
|
||||||
|
KeyLabel,
|
||||||
|
RecComponent,
|
||||||
|
RecStrFuncComponent,
|
||||||
|
RecStrFuncUnknown,
|
||||||
|
Th,
|
||||||
|
} from '~/components/pub/custom-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue'))
|
||||||
|
|
||||||
|
const _doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cols: Col[] = [{}, {}, { width: 50 }]
|
||||||
|
|
||||||
|
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Aksi' }]]
|
||||||
|
|
||||||
|
export const keys = ['code', 'name', 'action']
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {
|
||||||
|
patient_address(_rec) {
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
data: any[]
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PubBaseDataTable
|
||||||
|
:rows="data"
|
||||||
|
:cols="cols"
|
||||||
|
:header="header"
|
||||||
|
:keys="keys"
|
||||||
|
:func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml"
|
||||||
|
:func-component="funcComponent"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Badge } from '~/components/pub/ui/badge'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rec: any
|
||||||
|
idx?: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusText = computed(() => {
|
||||||
|
return doctorStatus[props.rec.status_code as keyof typeof doctorStatus]
|
||||||
|
})
|
||||||
|
|
||||||
|
const badgeVariant = computed(() => {
|
||||||
|
return props.rec.status_code === 1 ? 'default' : 'destructive'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<Badge :variant="badgeVariant">
|
||||||
|
{{ statusText }}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Block from '~/components/pub/custom-ui/form/block.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: any }>()
|
||||||
|
const emit = defineEmits(['update:modelValue', 'event'])
|
||||||
|
|
||||||
|
const data = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (val) => emit('update:modelValue', val),
|
||||||
|
})
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{ value: '1', label: 'item 1' },
|
||||||
|
{ value: '2', label: 'item 2' },
|
||||||
|
{ value: '3', label: 'item 3' },
|
||||||
|
{ value: '4', label: 'item 4' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="entry-form">
|
||||||
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<Block>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label>Nama</Label>
|
||||||
|
<Field>
|
||||||
|
<Input v-model="data.name" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label>Kode</Label>
|
||||||
|
<Field>
|
||||||
|
<Input v-model="data.code" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label>Item Group</Label>
|
||||||
|
<Field>
|
||||||
|
<Select :items="items" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label>UOM</Label>
|
||||||
|
<Field>
|
||||||
|
<Select :items="items" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label>Infra</Label>
|
||||||
|
<Field>
|
||||||
|
<Select :items="items" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label>Harga</Label>
|
||||||
|
<Field>
|
||||||
|
<Input v-model="data.price" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import type {
|
||||||
|
Col,
|
||||||
|
KeyLabel,
|
||||||
|
RecComponent,
|
||||||
|
RecStrFuncComponent,
|
||||||
|
RecStrFuncUnknown,
|
||||||
|
Th,
|
||||||
|
} from '~/components/pub/custom-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue'))
|
||||||
|
|
||||||
|
const _doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cols: Col[] = [{}, {}, { width: 50 }]
|
||||||
|
|
||||||
|
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Aksi' }]]
|
||||||
|
|
||||||
|
export const keys = ['code', 'name', 'action']
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {
|
||||||
|
patient_address(_rec) {
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
data: any[]
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PubBaseDataTable
|
||||||
|
:rows="data"
|
||||||
|
:cols="cols"
|
||||||
|
:header="header"
|
||||||
|
:keys="keys"
|
||||||
|
:func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml"
|
||||||
|
:func-component="funcComponent"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Badge } from '~/components/pub/ui/badge'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rec: any
|
||||||
|
idx?: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusText = computed(() => {
|
||||||
|
return doctorStatus[props.rec.status_code as keyof typeof doctorStatus]
|
||||||
|
})
|
||||||
|
|
||||||
|
const badgeVariant = computed(() => {
|
||||||
|
return props.rec.status_code === 1 ? 'default' : 'destructive'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<Badge :variant="badgeVariant">
|
||||||
|
{{ statusText }}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Block from '~/components/pub/custom-ui/form/block.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: any }>()
|
||||||
|
const emit = defineEmits(['update:modelValue', 'event'])
|
||||||
|
|
||||||
|
const data = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (val) => emit('update:modelValue', val),
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="entry-form">
|
||||||
|
<div class="mb-2 border-b border-b-slate-300 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<Block>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label>No. IHS</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import type {
|
||||||
|
Col,
|
||||||
|
KeyLabel,
|
||||||
|
RecComponent,
|
||||||
|
RecStrFuncComponent,
|
||||||
|
RecStrFuncUnknown,
|
||||||
|
Th,
|
||||||
|
} from '~/components/pub/custom-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
type SmallDetailDto = any
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue'))
|
||||||
|
const statusBadge = defineAsyncComponent(() => import('./status-badge.vue'))
|
||||||
|
|
||||||
|
const _doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cols: Col[] = [
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 250 },
|
||||||
|
{},
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 100 },
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 100 },
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const header: Th[][] = [
|
||||||
|
[
|
||||||
|
{ label: 'Kode JKN' },
|
||||||
|
{ label: 'Nama' },
|
||||||
|
{ label: 'No KTP' },
|
||||||
|
{ label: 'No SIP' },
|
||||||
|
{ label: 'No IHS' },
|
||||||
|
{ label: 'Telpon' },
|
||||||
|
{ label: 'Fee Ranap' },
|
||||||
|
{ label: 'Fee Rajal' },
|
||||||
|
{ label: 'Status' },
|
||||||
|
{ label: '' },
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
export const keys = [
|
||||||
|
'bpjs_code',
|
||||||
|
'name',
|
||||||
|
'identity_number',
|
||||||
|
'sip_no',
|
||||||
|
'ihs_number',
|
||||||
|
'phone',
|
||||||
|
'inPatient_itemPrice',
|
||||||
|
'outPatient_itemPrice',
|
||||||
|
'status',
|
||||||
|
'action',
|
||||||
|
]
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {
|
||||||
|
name: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||||
|
},
|
||||||
|
identity_number: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||||
|
return '(TANPA NIK)'
|
||||||
|
}
|
||||||
|
return recX.identity_number
|
||||||
|
},
|
||||||
|
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||||
|
},
|
||||||
|
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
status(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: statusBadge,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {
|
||||||
|
patient_address(_rec) {
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
data: any[]
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PubBaseDataTable
|
||||||
|
:rows="data"
|
||||||
|
:cols="cols"
|
||||||
|
:header="header"
|
||||||
|
:keys="keys"
|
||||||
|
:func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml"
|
||||||
|
:func-component="funcComponent"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Badge } from '~/components/pub/ui/badge'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rec: any
|
||||||
|
idx?: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusText = computed(() => {
|
||||||
|
return doctorStatus[props.rec.status_code as keyof typeof doctorStatus]
|
||||||
|
})
|
||||||
|
|
||||||
|
const badgeVariant = computed(() => {
|
||||||
|
return props.rec.status_code === 1 ? 'default' : 'destructive'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<Badge :variant="badgeVariant">
|
||||||
|
{{ statusText }}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Block from '~/components/pub/custom-ui/form/block.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: any }>()
|
||||||
|
const emit = defineEmits(['update:modelValue', 'event'])
|
||||||
|
|
||||||
|
const data = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (val) => emit('update:modelValue', val),
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="entry-form">
|
||||||
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<Block>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label>Nama</Label>
|
||||||
|
<Field>
|
||||||
|
<Input v-model="data.name" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label>Kode</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import type {
|
||||||
|
Col,
|
||||||
|
KeyLabel,
|
||||||
|
RecComponent,
|
||||||
|
RecStrFuncComponent,
|
||||||
|
RecStrFuncUnknown,
|
||||||
|
Th,
|
||||||
|
} from '~/components/pub/custom-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue'))
|
||||||
|
|
||||||
|
const _doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cols: Col[] = [{}, {}, { width: 50 }]
|
||||||
|
|
||||||
|
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Aksi' }]]
|
||||||
|
|
||||||
|
export const keys = ['code', 'name', 'action']
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {
|
||||||
|
patient_address(_rec) {
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
data: any[]
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PubBaseDataTable
|
||||||
|
:rows="data"
|
||||||
|
:cols="cols"
|
||||||
|
:header="header"
|
||||||
|
:keys="keys"
|
||||||
|
:func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml"
|
||||||
|
:func-component="funcComponent"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Badge } from '~/components/pub/ui/badge'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rec: any
|
||||||
|
idx?: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusText = computed(() => {
|
||||||
|
return doctorStatus[props.rec.status_code as keyof typeof doctorStatus]
|
||||||
|
})
|
||||||
|
|
||||||
|
const badgeVariant = computed(() => {
|
||||||
|
return props.rec.status_code === 1 ? 'default' : 'destructive'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<Badge :variant="badgeVariant">
|
||||||
|
{{ statusText }}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Block from '~/components/pub/custom-ui/form/block.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: any }>()
|
||||||
|
const emit = defineEmits(['update:modelValue', 'event'])
|
||||||
|
|
||||||
|
const data = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (val) => emit('update:modelValue', val),
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="entry-form">
|
||||||
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<Block>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label>Nama</Label>
|
||||||
|
<Field>
|
||||||
|
<Input v-model="data.name" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label>Kode</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import type {
|
||||||
|
Col,
|
||||||
|
KeyLabel,
|
||||||
|
RecComponent,
|
||||||
|
RecStrFuncComponent,
|
||||||
|
RecStrFuncUnknown,
|
||||||
|
Th,
|
||||||
|
} from '~/components/pub/custom-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue'))
|
||||||
|
|
||||||
|
const _doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cols: Col[] = [{}, {}, { width: 50 }]
|
||||||
|
|
||||||
|
export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Aksi' }]]
|
||||||
|
|
||||||
|
export const keys = ['code', 'name', 'action']
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {
|
||||||
|
patient_address(_rec) {
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
data: any[]
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PubBaseDataTable
|
||||||
|
:rows="data"
|
||||||
|
:cols="cols"
|
||||||
|
:header="header"
|
||||||
|
:keys="keys"
|
||||||
|
:func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml"
|
||||||
|
:func-component="funcComponent"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Block from '~/components/pub/custom-ui/form/block.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: any }>()
|
||||||
|
const emit = defineEmits(['update:modelValue', 'event'])
|
||||||
|
|
||||||
|
const data = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (val) => emit('update:modelValue', val),
|
||||||
|
})
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{ value: '1', label: 'item 1' },
|
||||||
|
{ value: '2', label: 'item 2' },
|
||||||
|
{ value: '3', label: 'item 3' },
|
||||||
|
{ value: '4', label: 'item 4' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="entry-form">
|
||||||
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<Block>
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label>Nama</Label>
|
||||||
|
<Field>
|
||||||
|
<Input type="text" name="identity_number" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label>Kode</Label>
|
||||||
|
<Field name="sip_number">
|
||||||
|
<Input type="text" name="sip_no" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label>Metode Pemberian</Label>
|
||||||
|
<Field name="phone">
|
||||||
|
<Select :items="items" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label>Bentuk Sediaan</Label>
|
||||||
|
<Field>
|
||||||
|
<Select :items="items" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label>Dosis</Label>
|
||||||
|
<Field>
|
||||||
|
<Input type="number" name="outPatient_rate" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label>Infra</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label>Stock</Label>
|
||||||
|
<Field>
|
||||||
|
<Input type="number" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label>Status</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import type {
|
||||||
|
Col,
|
||||||
|
KeyLabel,
|
||||||
|
RecComponent,
|
||||||
|
RecStrFuncComponent,
|
||||||
|
RecStrFuncUnknown,
|
||||||
|
Th,
|
||||||
|
} from '~/components/pub/custom-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
type SmallDetailDto = any
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue'))
|
||||||
|
|
||||||
|
export const cols: Col[] = [{}, {}, {}, {}, {}, {}, { width: 50 }]
|
||||||
|
|
||||||
|
export const header: Th[][] = [
|
||||||
|
[
|
||||||
|
{ label: 'Kode' },
|
||||||
|
{ label: 'Name' },
|
||||||
|
{ label: 'Kategori' },
|
||||||
|
{ label: 'Golongan' },
|
||||||
|
{ label: 'Metode Pemberian' },
|
||||||
|
{ label: 'Bentuk' },
|
||||||
|
{ label: 'Stok' },
|
||||||
|
{ label: 'Aksi' },
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
export const keys = ['code', 'name', 'category', 'group', 'method', 'unit', 'total', 'action']
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {
|
||||||
|
cateogry: (rec: unknown): unknown => {
|
||||||
|
return (rec as SmallDetailDto).medicineCategory?.name || '-'
|
||||||
|
},
|
||||||
|
group: (rec: unknown): unknown => {
|
||||||
|
return (rec as SmallDetailDto).medicineGroup?.name || '-'
|
||||||
|
},
|
||||||
|
method: (rec: unknown): unknown => {
|
||||||
|
return (rec as SmallDetailDto).medicineMethod?.name || '-'
|
||||||
|
},
|
||||||
|
unit: (rec: unknown): unknown => {
|
||||||
|
return (rec as SmallDetailDto).medicineUnit?.name || '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action: (rec: unknown, idx: number): RecComponent => {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {
|
||||||
|
// (_rec) {
|
||||||
|
// return '-'
|
||||||
|
// },
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
data: any[]
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PubBaseDataTable
|
||||||
|
:rows="data"
|
||||||
|
:cols="cols"
|
||||||
|
:header="header"
|
||||||
|
:keys="keys"
|
||||||
|
:func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml"
|
||||||
|
:func-component="funcComponent"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Badge } from '~/components/pub/ui/badge'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rec: any
|
||||||
|
idx?: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusText = computed(() => {
|
||||||
|
return doctorStatus[props.rec.status_code as keyof typeof doctorStatus]
|
||||||
|
})
|
||||||
|
|
||||||
|
const badgeVariant = computed(() => {
|
||||||
|
return props.rec.status_code === 1 ? 'default' : 'destructive'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<Badge :variant="badgeVariant">
|
||||||
|
{{ statusText }}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Block from '~/components/pub/custom-ui/form/block.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: any }>()
|
||||||
|
const emit = defineEmits(['update:modelValue', 'event'])
|
||||||
|
|
||||||
|
const data = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (val) => emit('update:modelValue', val),
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="entry-form">
|
||||||
|
<div class="mb-2 border-b border-b-slate-300 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<Block>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label>No. IHS</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import type {
|
||||||
|
Col,
|
||||||
|
KeyLabel,
|
||||||
|
RecComponent,
|
||||||
|
RecStrFuncComponent,
|
||||||
|
RecStrFuncUnknown,
|
||||||
|
Th,
|
||||||
|
} from '~/components/pub/custom-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
type SmallDetailDto = any
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue'))
|
||||||
|
const statusBadge = defineAsyncComponent(() => import('./status-badge.vue'))
|
||||||
|
|
||||||
|
const _doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cols: Col[] = [
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 250 },
|
||||||
|
{},
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 100 },
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 100 },
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const header: Th[][] = [
|
||||||
|
[
|
||||||
|
{ label: 'Kode JKN' },
|
||||||
|
{ label: 'Nama' },
|
||||||
|
{ label: 'No KTP' },
|
||||||
|
{ label: 'No SIP' },
|
||||||
|
{ label: 'No IHS' },
|
||||||
|
{ label: 'Telpon' },
|
||||||
|
{ label: 'Fee Ranap' },
|
||||||
|
{ label: 'Fee Rajal' },
|
||||||
|
{ label: 'Status' },
|
||||||
|
{ label: '' },
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
export const keys = [
|
||||||
|
'bpjs_code',
|
||||||
|
'name',
|
||||||
|
'identity_number',
|
||||||
|
'sip_no',
|
||||||
|
'ihs_number',
|
||||||
|
'phone',
|
||||||
|
'inPatient_itemPrice',
|
||||||
|
'outPatient_itemPrice',
|
||||||
|
'status',
|
||||||
|
'action',
|
||||||
|
]
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {
|
||||||
|
name: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||||
|
},
|
||||||
|
identity_number: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||||
|
return '(TANPA NIK)'
|
||||||
|
}
|
||||||
|
return recX.identity_number
|
||||||
|
},
|
||||||
|
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||||
|
},
|
||||||
|
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
status(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: statusBadge,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {
|
||||||
|
patient_address(_rec) {
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
data: any[]
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PubBaseDataTable
|
||||||
|
:rows="data"
|
||||||
|
:cols="cols"
|
||||||
|
:header="header"
|
||||||
|
:keys="keys"
|
||||||
|
:func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml"
|
||||||
|
:func-component="funcComponent"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Badge } from '~/components/pub/ui/badge'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rec: any
|
||||||
|
idx?: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusText = computed(() => {
|
||||||
|
return doctorStatus[props.rec.status_code as keyof typeof doctorStatus]
|
||||||
|
})
|
||||||
|
|
||||||
|
const badgeVariant = computed(() => {
|
||||||
|
return props.rec.status_code === 1 ? 'default' : 'destructive'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<Badge :variant="badgeVariant">
|
||||||
|
{{ statusText }}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Block from '~/components/pub/custom-ui/form/block.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: any }>()
|
||||||
|
const emit = defineEmits(['update:modelValue', 'event'])
|
||||||
|
|
||||||
|
const data = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (val) => emit('update:modelValue', val),
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="entry-form">
|
||||||
|
<div class="mb-2 border-b border-b-slate-300 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<Block>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label>No. IHS</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import type {
|
||||||
|
Col,
|
||||||
|
KeyLabel,
|
||||||
|
RecComponent,
|
||||||
|
RecStrFuncComponent,
|
||||||
|
RecStrFuncUnknown,
|
||||||
|
Th,
|
||||||
|
} from '~/components/pub/custom-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
type SmallDetailDto = any
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue'))
|
||||||
|
const statusBadge = defineAsyncComponent(() => import('./status-badge.vue'))
|
||||||
|
|
||||||
|
const _doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cols: Col[] = [
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 250 },
|
||||||
|
{},
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 100 },
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 100 },
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const header: Th[][] = [
|
||||||
|
[
|
||||||
|
{ label: 'Kode JKN' },
|
||||||
|
{ label: 'Nama' },
|
||||||
|
{ label: 'No KTP' },
|
||||||
|
{ label: 'No SIP' },
|
||||||
|
{ label: 'No IHS' },
|
||||||
|
{ label: 'Telpon' },
|
||||||
|
{ label: 'Fee Ranap' },
|
||||||
|
{ label: 'Fee Rajal' },
|
||||||
|
{ label: 'Status' },
|
||||||
|
{ label: '' },
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
export const keys = [
|
||||||
|
'bpjs_code',
|
||||||
|
'name',
|
||||||
|
'identity_number',
|
||||||
|
'sip_no',
|
||||||
|
'ihs_number',
|
||||||
|
'phone',
|
||||||
|
'inPatient_itemPrice',
|
||||||
|
'outPatient_itemPrice',
|
||||||
|
'status',
|
||||||
|
'action',
|
||||||
|
]
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {
|
||||||
|
name: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||||
|
},
|
||||||
|
identity_number: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||||
|
return '(TANPA NIK)'
|
||||||
|
}
|
||||||
|
return recX.identity_number
|
||||||
|
},
|
||||||
|
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||||
|
},
|
||||||
|
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
status(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: statusBadge,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {
|
||||||
|
patient_address(_rec) {
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
data: any[]
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PubBaseDataTable
|
||||||
|
:rows="data"
|
||||||
|
:cols="cols"
|
||||||
|
:header="header"
|
||||||
|
:keys="keys"
|
||||||
|
:func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml"
|
||||||
|
:func-component="funcComponent"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Badge } from '~/components/pub/ui/badge'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rec: any
|
||||||
|
idx?: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusText = computed(() => {
|
||||||
|
return doctorStatus[props.rec.status_code as keyof typeof doctorStatus]
|
||||||
|
})
|
||||||
|
|
||||||
|
const badgeVariant = computed(() => {
|
||||||
|
return props.rec.status_code === 1 ? 'default' : 'destructive'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<Badge :variant="badgeVariant">
|
||||||
|
{{ statusText }}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Block from '~/components/pub/custom-ui/form/block.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
import Action from '~/components/pub/custom-ui/nav-footer/ba-dr-su.vue'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="entry-form">
|
||||||
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||||
|
<Block>
|
||||||
|
<FieldGroup :column="3">
|
||||||
|
<Label>Nama</Label>
|
||||||
|
<Field>
|
||||||
|
<Input type="text" name="name" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup :column="3">
|
||||||
|
<Label>Nama</Label>
|
||||||
|
<Field>
|
||||||
|
<Input type="text" name="name" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup :column="3">
|
||||||
|
<Label>Nomor RM</Label>
|
||||||
|
<Field>
|
||||||
|
<Input type="text" name="name" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label dynamic>Alamat</Label>
|
||||||
|
<Field>
|
||||||
|
<Input type="text" name="name" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
<div class="my-2 flex justify-end py-2">
|
||||||
|
<Action />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
import type {
|
||||||
|
Col,
|
||||||
|
KeyLabel,
|
||||||
|
RecComponent,
|
||||||
|
RecStrFuncComponent,
|
||||||
|
RecStrFuncUnknown,
|
||||||
|
Th,
|
||||||
|
} from '~/components/pub/custom-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
type SmallDetailDto = any
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue'))
|
||||||
|
const statusBadge = defineAsyncComponent(() => import('./status-badge.vue'))
|
||||||
|
|
||||||
|
export const cols: Col[] = [
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 120 },
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 100 },
|
||||||
|
{},
|
||||||
|
{ width: 50 },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const header: Th[][] = [
|
||||||
|
[
|
||||||
|
{ label: 'Nama' },
|
||||||
|
{ label: 'Rekam Medis' },
|
||||||
|
{ label: 'KTP' },
|
||||||
|
{ label: 'Tgl Lahir' },
|
||||||
|
{ label: 'Umur' },
|
||||||
|
{ label: 'JK' },
|
||||||
|
{ label: 'Pendidikan' },
|
||||||
|
{ label: 'Status' },
|
||||||
|
{ label: '' },
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
export const keys = [
|
||||||
|
'name',
|
||||||
|
'medicalRecord_number',
|
||||||
|
'identity_number',
|
||||||
|
'birth_date',
|
||||||
|
'patient_age',
|
||||||
|
'gender',
|
||||||
|
'education',
|
||||||
|
'status',
|
||||||
|
'action',
|
||||||
|
]
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {
|
||||||
|
name: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return `${recX.firstName} ${recX.middleName || ''} ${recX.lastName || ''}`
|
||||||
|
},
|
||||||
|
identity_number: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||||
|
return '(TANPA NIK)'
|
||||||
|
}
|
||||||
|
return recX.identity_number
|
||||||
|
},
|
||||||
|
birth_date: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
if (typeof recX.birth_date == 'object' && recX.birth_date) {
|
||||||
|
return (recX.birth_date as Date).toLocaleDateString()
|
||||||
|
} else if (typeof recX.birth_date == 'string') {
|
||||||
|
return (recX.birth_date as string).substring(0, 10)
|
||||||
|
}
|
||||||
|
return recX.birth_date
|
||||||
|
},
|
||||||
|
patient_age: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return recX.birth_date?.split('T')[0]
|
||||||
|
},
|
||||||
|
gender: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
if (typeof recX?.gender_code !== 'number' && recX?.gender_code !== '') {
|
||||||
|
return 'Tidak Diketahui'
|
||||||
|
}
|
||||||
|
return recX.gender_code
|
||||||
|
},
|
||||||
|
education: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
if (typeof recX.education_code == 'number' && recX.education_code >= 0) {
|
||||||
|
return recX.education_code
|
||||||
|
} else if (typeof recX.education_code) {
|
||||||
|
return recX.education_code
|
||||||
|
}
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
status(rec, idx) {
|
||||||
|
if (rec.status === null) {
|
||||||
|
rec.status_code = 0
|
||||||
|
}
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: statusBadge,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {
|
||||||
|
patient_address(_rec) {
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
data: any[]
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PubBaseDataTable
|
||||||
|
:rows="data"
|
||||||
|
:cols="cols"
|
||||||
|
:header="header"
|
||||||
|
:keys="keys"
|
||||||
|
:func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml"
|
||||||
|
:func-component="funcComponent"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Badge } from '~/components/pub/ui/badge'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rec: any
|
||||||
|
idx?: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusText = computed(() => {
|
||||||
|
return doctorStatus[props.rec.status_code as keyof typeof doctorStatus]
|
||||||
|
})
|
||||||
|
|
||||||
|
const badgeVariant = computed(() => {
|
||||||
|
return props.rec.status_code === 1 ? 'default' : 'destructive'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<Badge :variant="badgeVariant">
|
||||||
|
{{ statusText }}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { FormErrors } from '~/types/error'
|
||||||
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
import Block from '~/components/pub/custom-ui/form/block.vue'
|
||||||
|
import Combobox from '~/components/pub/custom-ui/form/combobox.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
import { educationCodes, genderCodes, occupationCodes, religionCodes } from '~/lib/constants'
|
||||||
|
import { mapToComboboxOptList } from '~/lib/utils'
|
||||||
|
|
||||||
|
interface DivisionFormData {
|
||||||
|
name: string
|
||||||
|
code: string
|
||||||
|
parentId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
division: {
|
||||||
|
msg: {
|
||||||
|
placeholder: string
|
||||||
|
search: string
|
||||||
|
empty: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items: {
|
||||||
|
value: string
|
||||||
|
label: string
|
||||||
|
code: string
|
||||||
|
}[]
|
||||||
|
schema: any
|
||||||
|
initialValues?: Partial<DivisionFormData>
|
||||||
|
errors?: FormErrors
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
submit: [values: DivisionFormData, resetForm: () => void]
|
||||||
|
cancel: [resetForm: () => void]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const educationOpts = mapToComboboxOptList(educationCodes)
|
||||||
|
const occupationOpts = mapToComboboxOptList(occupationCodes)
|
||||||
|
const religionOpts = mapToComboboxOptList(religionCodes)
|
||||||
|
const genderOpts = mapToComboboxOptList(genderCodes)
|
||||||
|
|
||||||
|
const formSchema = toTypedSchema(props.schema)
|
||||||
|
|
||||||
|
// Form submission handler
|
||||||
|
function onSubmitForm(values: any, { resetForm }: { resetForm: () => void }) {
|
||||||
|
const formData: DivisionFormData = {
|
||||||
|
name: values.name || '',
|
||||||
|
code: values.code || '',
|
||||||
|
parentId: values.parentId || '',
|
||||||
|
}
|
||||||
|
emit('submit', formData, resetForm)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Form
|
||||||
|
v-slot="{ handleSubmit, resetForm }"
|
||||||
|
as=""
|
||||||
|
keep-values
|
||||||
|
:validation-schema="formSchema"
|
||||||
|
:initial-values="initialValues"
|
||||||
|
>
|
||||||
|
<form id="entry-form" @submit="handleSubmit($event, (values) => onSubmitForm(values, { resetForm }))">
|
||||||
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<Block>
|
||||||
|
<!-- LocationType -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="locationType">Jenis Alamat</Label>
|
||||||
|
<Field id="locationType" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="locationType">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Select id="locationType" v-bind="componentField" :items="genderOpts" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Address -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="address">Alamat</Label>
|
||||||
|
<Field id="address" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="address">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="address"
|
||||||
|
type="text"
|
||||||
|
placeholder="Masukkan alamat lengkap"
|
||||||
|
autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Rt -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="rt">RT</Label>
|
||||||
|
<Field id="rt" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="rt">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="rt"
|
||||||
|
type="text"
|
||||||
|
maxlength="2"
|
||||||
|
placeholder="01"
|
||||||
|
autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Rw -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="rw">RW</Label>
|
||||||
|
<Field id="rw" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="rw">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="rw"
|
||||||
|
type="text"
|
||||||
|
maxlength="2"
|
||||||
|
placeholder="01"
|
||||||
|
autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Village_Code -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="villageCode">Desa/Kelurahan</Label>
|
||||||
|
<Field id="villageCode" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="villageCode">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Combobox id="villageCode" v-bind="componentField" :items="genderOpts" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { FormErrors } from '~/types/error'
|
||||||
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
import Block from '~/components/pub/custom-ui/form/block.vue'
|
||||||
|
import Combobox from '~/components/pub/custom-ui/form/combobox.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
import { educationCodes, genderCodes, occupationCodes, religionCodes } from '~/lib/constants'
|
||||||
|
import { mapToComboboxOptList } from '~/lib/utils'
|
||||||
|
|
||||||
|
interface DivisionFormData {
|
||||||
|
name: string
|
||||||
|
code: string
|
||||||
|
parentId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
division: {
|
||||||
|
msg: {
|
||||||
|
placeholder: string
|
||||||
|
search: string
|
||||||
|
empty: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items: {
|
||||||
|
value: string
|
||||||
|
label: string
|
||||||
|
code: string
|
||||||
|
}[]
|
||||||
|
schema: any
|
||||||
|
initialValues?: Partial<DivisionFormData>
|
||||||
|
errors?: FormErrors
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
submit: [values: DivisionFormData, resetForm: () => void]
|
||||||
|
cancel: [resetForm: () => void]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const educationOpts = mapToComboboxOptList(educationCodes)
|
||||||
|
const occupationOpts = mapToComboboxOptList(occupationCodes)
|
||||||
|
const religionOpts = mapToComboboxOptList(religionCodes)
|
||||||
|
const genderOpts = mapToComboboxOptList(genderCodes)
|
||||||
|
|
||||||
|
const formSchema = toTypedSchema(props.schema)
|
||||||
|
|
||||||
|
// Form submission handler
|
||||||
|
function onSubmitForm(values: any, { resetForm }: { resetForm: () => void }) {
|
||||||
|
const formData: DivisionFormData = {
|
||||||
|
name: values.name || '',
|
||||||
|
code: values.code || '',
|
||||||
|
parentId: values.parentId || '',
|
||||||
|
}
|
||||||
|
emit('submit', formData, resetForm)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Form
|
||||||
|
v-slot="{ handleSubmit, resetForm }"
|
||||||
|
as=""
|
||||||
|
keep-values
|
||||||
|
:validation-schema="formSchema"
|
||||||
|
:initial-values="initialValues"
|
||||||
|
>
|
||||||
|
<form id="entry-form" @submit="handleSubmit($event, (values) => onSubmitForm(values, { resetForm }))">
|
||||||
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<Block>
|
||||||
|
<!-- LocationType -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="type">Tipe</Label>
|
||||||
|
<Field id="type" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="type">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Select id="type" v-bind="componentField" :items="genderOpts" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Address -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="value">Value</Label>
|
||||||
|
<Field id="value" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="value">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="value"
|
||||||
|
type="text"
|
||||||
|
placeholder="Masukkan alamat lengkap"
|
||||||
|
autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,234 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { FormErrors } from '~/types/error'
|
||||||
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
import Block from '~/components/pub/custom-ui/form/block.vue'
|
||||||
|
import Combobox from '~/components/pub/custom-ui/form/combobox.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
import { educationCodes, genderCodes, occupationCodes, religionCodes, relationshipCodes } from '~/lib/constants'
|
||||||
|
import { mapToComboboxOptList } from '~/lib/utils'
|
||||||
|
|
||||||
|
interface DivisionFormData {
|
||||||
|
name: string
|
||||||
|
code: string
|
||||||
|
parentId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
division: {
|
||||||
|
msg: {
|
||||||
|
placeholder: string
|
||||||
|
search: string
|
||||||
|
empty: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items: {
|
||||||
|
value: string
|
||||||
|
label: string
|
||||||
|
code: string
|
||||||
|
}[]
|
||||||
|
schema: any
|
||||||
|
initialValues?: Partial<DivisionFormData>
|
||||||
|
errors?: FormErrors
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
submit: [values: DivisionFormData, resetForm: () => void]
|
||||||
|
cancel: [resetForm: () => void]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const relationshipOpts = mapToComboboxOptList(relationshipCodes)
|
||||||
|
const educationOpts = mapToComboboxOptList(educationCodes)
|
||||||
|
const occupationOpts = mapToComboboxOptList(occupationCodes)
|
||||||
|
const genderOpts = mapToComboboxOptList(genderCodes)
|
||||||
|
|
||||||
|
const formSchema = toTypedSchema(props.schema)
|
||||||
|
|
||||||
|
// Form submission handler
|
||||||
|
function onSubmitForm(values: any, { resetForm }: { resetForm: () => void }) {
|
||||||
|
const formData: DivisionFormData = {
|
||||||
|
name: values.name || '',
|
||||||
|
code: values.code || '',
|
||||||
|
parentId: values.parentId || '',
|
||||||
|
}
|
||||||
|
emit('submit', formData, resetForm)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Form
|
||||||
|
v-slot="{ handleSubmit, resetForm }"
|
||||||
|
as=""
|
||||||
|
keep-values
|
||||||
|
:validation-schema="formSchema"
|
||||||
|
:initial-values="initialValues"
|
||||||
|
>
|
||||||
|
<form id="entry-form" @submit="handleSubmit($event, (values) => onSubmitForm(values, { resetForm }))">
|
||||||
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<Block>
|
||||||
|
<!-- Relationship_Code -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="relationshipCode">Hubungan</Label>
|
||||||
|
<Field id="relationshipCode" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="relationshipCode">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Select id="relationshipCode" v-bind="componentField" :items="relationshipOpts" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Name -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="relativeName">Nama</Label>
|
||||||
|
<Field id="relativeName" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="relativeName">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="relativeName"
|
||||||
|
type="text"
|
||||||
|
placeholder="Masukkan nama kerabat"
|
||||||
|
autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Address -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="relativeAddress">Alamat</Label>
|
||||||
|
<Field id="relativeAddress" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="relativeAddress">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="relativeAddress"
|
||||||
|
type="text"
|
||||||
|
placeholder="Alamat kerabat"
|
||||||
|
autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Village_Code -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="relativeVillageCode">Desa/Kelurahan</Label>
|
||||||
|
<Field id="relativeVillageCode" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="relativeVillageCode">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Combobox id="relativeVillageCode" v-bind="componentField" :items="genderOpts" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Gender_Code -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="relativeGender">Jenis Kelamin</Label>
|
||||||
|
<Field id="relativeGender" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="relativeGender">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Select id="relativeGender" v-bind="componentField" :items="genderOpts" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- PhoneNumber -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="phoneNumber">Nomor Telepon</Label>
|
||||||
|
<Field id="phoneNumber" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="phoneNumber">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="phoneNumber"
|
||||||
|
type="text"
|
||||||
|
placeholder="0812xxxxxx"
|
||||||
|
autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Education_Code -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="relativeEducation">Pendidikan</Label>
|
||||||
|
<Field id="relativeEducation" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="relativeEducation">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Select id="relativeEducation" v-bind="componentField" :items="educationOpts" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Occupation_Code -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="relativeOccupationCode">Pekerjaan</Label>
|
||||||
|
<Field id="relativeOccupationCode" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="relativeOccupationCode">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Select id="relativeOccupationCode" v-bind="componentField" :items="occupationOpts" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Occupation_Name -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="relativeOccupationName">Nama Pekerjaan</Label>
|
||||||
|
<Field id="relativeOccupationName" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="relativeOccupationName">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="relativeOccupationName"
|
||||||
|
type="text"
|
||||||
|
placeholder="Contoh: Guru, Dokter, Petani"
|
||||||
|
autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,340 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { FormErrors } from '~/types/error'
|
||||||
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
import Block from '~/components/pub/custom-ui/form/block.vue'
|
||||||
|
import Combobox from '~/components/pub/custom-ui/form/combobox.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
import { educationCodes, genderCodes, occupationCodes, religionCodes } from '~/lib/constants'
|
||||||
|
import { mapToComboboxOptList } from '~/lib/utils'
|
||||||
|
|
||||||
|
interface DivisionFormData {
|
||||||
|
name: string
|
||||||
|
code: string
|
||||||
|
parentId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
division: {
|
||||||
|
msg: {
|
||||||
|
placeholder: string
|
||||||
|
search: string
|
||||||
|
empty: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items: {
|
||||||
|
value: string
|
||||||
|
label: string
|
||||||
|
code: string
|
||||||
|
}[]
|
||||||
|
schema: any
|
||||||
|
initialValues?: Partial<DivisionFormData>
|
||||||
|
errors?: FormErrors
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
submit: [values: DivisionFormData, resetForm: () => void]
|
||||||
|
cancel: [resetForm: () => void]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const educationOpts = mapToComboboxOptList(educationCodes)
|
||||||
|
const occupationOpts = mapToComboboxOptList(occupationCodes)
|
||||||
|
const religionOpts = mapToComboboxOptList(religionCodes)
|
||||||
|
const genderOpts = mapToComboboxOptList(genderCodes)
|
||||||
|
|
||||||
|
const formSchema = toTypedSchema(props.schema)
|
||||||
|
|
||||||
|
// Form submission handler
|
||||||
|
function onSubmitForm(values: any, { resetForm }: { resetForm: () => void }) {
|
||||||
|
const formData: DivisionFormData = {
|
||||||
|
name: values.name || '',
|
||||||
|
code: values.code || '',
|
||||||
|
parentId: values.parentId || '',
|
||||||
|
}
|
||||||
|
emit('submit', formData, resetForm)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Form
|
||||||
|
v-slot="{ handleSubmit, resetForm }"
|
||||||
|
as=""
|
||||||
|
keep-values
|
||||||
|
:validation-schema="formSchema"
|
||||||
|
:initial-values="initialValues"
|
||||||
|
>
|
||||||
|
<form id="entry-form" @submit="handleSubmit($event, (values) => onSubmitForm(values, { resetForm }))">
|
||||||
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<Block>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="residentIdentityNumber">KTP</Label>
|
||||||
|
<Field id="residentIdentityNumber" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="residentIdentityNumber">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="residentIdentityNumber"
|
||||||
|
type="text"
|
||||||
|
maxlength="16"
|
||||||
|
placeholder="Nomor KTP"
|
||||||
|
autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- FrontTitle -->
|
||||||
|
<FieldGroup :column="3">
|
||||||
|
<Label label-for="frontTitle">Gelar Depan</Label>
|
||||||
|
<Field id="frontTitle" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="frontTitle">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="frontTitle"
|
||||||
|
type="text"
|
||||||
|
placeholder="Dr., Ir., dll"
|
||||||
|
autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<FieldGroup :column="3">
|
||||||
|
<Label label-for="name" position="dynamic">Nama</Label>
|
||||||
|
<Field id="name" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="name">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="name"
|
||||||
|
type="text"
|
||||||
|
placeholder="Nama lengkap"
|
||||||
|
autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- EndTitle -->
|
||||||
|
<FieldGroup :column="3">
|
||||||
|
<Label label-for="endTitle" position="dynamic">Gelar Belakang</Label>
|
||||||
|
<Field id="endTitle" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="endTitle">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="endTitle"
|
||||||
|
type="text"
|
||||||
|
placeholder="S.Kom, M.Kes, dll"
|
||||||
|
autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- BirthDate -->
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label label-for="birthDate">Tanggal Lahir</Label>
|
||||||
|
<Field id="birthDate" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="birthDate">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input id="birthDate" type="date" v-bind="componentField" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- BirthRegency_Code -->
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label label-for="birthRegencyCode">Tempat Lahir</Label>
|
||||||
|
<Field id="birthRegencyCode" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="birthRegencyCode">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Combobox id="parentId" v-bind="componentField" :items="educationOpts" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Gender_Code -->
|
||||||
|
<FieldGroup>
|
||||||
|
<Label label-for="genderCode">Jenis Kelamin</Label>
|
||||||
|
<Field id="genderCode" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="genderCode">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Combobox id="genderCode" v-bind="componentField" :items="genderOpts" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- PassportNumber -->
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label label-for="passportNumber">Paspor</Label>
|
||||||
|
<Field id="passportNumber" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="passportNumber">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="passportNumber"
|
||||||
|
type="text"
|
||||||
|
placeholder="Nomor Paspor"
|
||||||
|
autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- DrivingLicenseNumber -->
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label label-for="drivingLicenseNumber">SIM</Label>
|
||||||
|
<Field id="drivingLicenseNumber" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="drivingLicenseNumber">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="drivingLicenseNumber"
|
||||||
|
type="text"
|
||||||
|
placeholder="Nomor SIM"
|
||||||
|
autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Religion_Code -->
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label label-for="religionCode">Agama</Label>
|
||||||
|
<Field id="religionCode" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="religionCode">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Combobox id="religionCode" v-bind="componentField" :items="religionOpts" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label label-for="ethnicCode">Suku</Label>
|
||||||
|
<Field id="ethnicCode" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="ethnicCode">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Combobox id="ethnicCode" v-bind="componentField" :items="occupationOpts" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Language_Code -->
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label label-for="languageCode">Bahasa</Label>
|
||||||
|
<Field id="languageCode" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="languageCode">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Combobox id="parentId" v-bind="componentField" :items="educationOpts" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Education_Code -->
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label label-for="educationCode">Pendidikan</Label>
|
||||||
|
<Field id="educationCode" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="educationCode">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Combobox id="educationCode" v-bind="componentField" :items="educationOpts" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Occupation_Code -->
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label label-for="occupationCode">Pekerjaan</Label>
|
||||||
|
<Field id="occupationCode" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="occupationCode">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Combobox id="occupationCode" v-bind="componentField" :items="occupationOpts" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
|
||||||
|
<!-- Occupation_Name -->
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label label-for="occupationName">Detail Pekerjaan</Label>
|
||||||
|
<Field id="occupationName" :errors="errors">
|
||||||
|
<FormField v-slot="{ componentField }" name="occupationName">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
id="occupationName"
|
||||||
|
type="text"
|
||||||
|
placeholder="Contoh: Guru SMP, Petani"
|
||||||
|
autocomplete="off"
|
||||||
|
v-bind="componentField"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Block from '~/components/pub/custom-ui/form/block.vue'
|
||||||
|
import FieldGroup from '~/components/pub/custom-ui/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/custom-ui/form/field.vue'
|
||||||
|
import Label from '~/components/pub/custom-ui/form/label.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: any }>()
|
||||||
|
const emit = defineEmits(['update:modelValue', 'event'])
|
||||||
|
|
||||||
|
const data = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (val) => emit('update:modelValue', val),
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="entry-form">
|
||||||
|
<div class="mb-2 border-b border-b-slate-300 text-lg xl:text-xl">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<Block>
|
||||||
|
<FieldGroup :column="2">
|
||||||
|
<Label>No. IHS</Label>
|
||||||
|
<Field>
|
||||||
|
<Input />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import type {
|
||||||
|
Col,
|
||||||
|
KeyLabel,
|
||||||
|
RecComponent,
|
||||||
|
RecStrFuncComponent,
|
||||||
|
RecStrFuncUnknown,
|
||||||
|
Th,
|
||||||
|
} from '~/components/pub/custom-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
type SmallDetailDto = any
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue'))
|
||||||
|
const statusBadge = defineAsyncComponent(() => import('./status-badge.vue'))
|
||||||
|
|
||||||
|
const _doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cols: Col[] = [
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 250 },
|
||||||
|
{},
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 100 },
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{ width: 120 },
|
||||||
|
{ width: 100 },
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const header: Th[][] = [
|
||||||
|
[
|
||||||
|
{ label: 'Kode JKN' },
|
||||||
|
{ label: 'Nama' },
|
||||||
|
{ label: 'No KTP' },
|
||||||
|
{ label: 'No SIP' },
|
||||||
|
{ label: 'No IHS' },
|
||||||
|
{ label: 'Telpon' },
|
||||||
|
{ label: 'Fee Ranap' },
|
||||||
|
{ label: 'Fee Rajal' },
|
||||||
|
{ label: 'Status' },
|
||||||
|
{ label: '' },
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
export const keys = [
|
||||||
|
'bpjs_code',
|
||||||
|
'name',
|
||||||
|
'identity_number',
|
||||||
|
'sip_no',
|
||||||
|
'ihs_number',
|
||||||
|
'phone',
|
||||||
|
'inPatient_itemPrice',
|
||||||
|
'outPatient_itemPrice',
|
||||||
|
'status',
|
||||||
|
'action',
|
||||||
|
]
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {
|
||||||
|
name: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim()
|
||||||
|
},
|
||||||
|
identity_number: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||||
|
return '(TANPA NIK)'
|
||||||
|
}
|
||||||
|
return recX.identity_number
|
||||||
|
},
|
||||||
|
inPatient_itemPrice: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
|
||||||
|
},
|
||||||
|
outPatient_itemPrice: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
status(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: statusBadge,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {
|
||||||
|
patient_address(_rec) {
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
data: any[]
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PubBaseDataTable
|
||||||
|
:rows="data"
|
||||||
|
:cols="cols"
|
||||||
|
:header="header"
|
||||||
|
:keys="keys"
|
||||||
|
:func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml"
|
||||||
|
:func-component="funcComponent"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Badge } from '~/components/pub/ui/badge'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rec: any
|
||||||
|
idx?: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const doctorStatus = {
|
||||||
|
0: 'Tidak Aktif',
|
||||||
|
1: 'Aktif',
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusText = computed(() => {
|
||||||
|
return doctorStatus[props.rec.status_code as keyof typeof doctorStatus]
|
||||||
|
})
|
||||||
|
|
||||||
|
const badgeVariant = computed(() => {
|
||||||
|
return props.rec.status_code === 1 ? 'default' : 'destructive'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<Badge :variant="badgeVariant">
|
||||||
|
{{ statusText }}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Block from '~/components/pub/form/block.vue'
|
||||||
|
import FieldGroup from '~/components/pub/form/field-group.vue'
|
||||||
|
import Field from '~/components/pub/form/field.vue'
|
||||||
|
import Label from '~/components/pub/form/label.vue'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="entry-form">
|
||||||
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||||
|
<Icon name="i-lucide-user" class="me-2" />
|
||||||
|
<span class="font-semibold">Tambah</span> Pasien
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
|
||||||
|
<Block>
|
||||||
|
<FieldGroup :column="3">
|
||||||
|
<Label>Nama</Label>
|
||||||
|
<Field>
|
||||||
|
<Input type="text" name="name" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup :column="3">
|
||||||
|
<Label>Nama</Label>
|
||||||
|
<Field>
|
||||||
|
<Input type="text" name="name" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup :column="3">
|
||||||
|
<Label>Nomor RM</Label>
|
||||||
|
<Field>
|
||||||
|
<Input type="text" name="name" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
<FieldGroup>
|
||||||
|
<Label dynamic>Alamat</Label>
|
||||||
|
<Field>
|
||||||
|
<Input type="text" name="name" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
<div class="my-2 flex justify-end py-2">
|
||||||
|
<PubNavFooterCsd />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
import type { Col, KeyLabel, RecComponent, RecStrFuncComponent, RecStrFuncUnknown, Th } from '~/components/pub/custom-ui/data/types'
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
type SmallDetailDto = any
|
||||||
|
|
||||||
|
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue'))
|
||||||
|
|
||||||
|
export const cols: Col[] = [
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 120 },
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{ width: 100 },
|
||||||
|
{ width: 100 },
|
||||||
|
{},
|
||||||
|
{ width: 50 },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const header: Th[][] = [
|
||||||
|
[
|
||||||
|
{ label: 'Nama' },
|
||||||
|
{ label: 'Rekam Medis' },
|
||||||
|
{ label: 'KTP' },
|
||||||
|
{ label: 'Tgl Lahir' },
|
||||||
|
{ label: 'Umur' },
|
||||||
|
{ label: 'JK' },
|
||||||
|
{ label: 'Pendidikan' },
|
||||||
|
{ label: 'Status' },
|
||||||
|
{ label: '' },
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
export const keys = [
|
||||||
|
'name',
|
||||||
|
'medicalRecord_number',
|
||||||
|
'identity_number',
|
||||||
|
'birth_date',
|
||||||
|
'patient_age',
|
||||||
|
'gender',
|
||||||
|
'education',
|
||||||
|
'status',
|
||||||
|
'action',
|
||||||
|
]
|
||||||
|
|
||||||
|
export const delKeyNames: KeyLabel[] = [
|
||||||
|
{ key: 'code', label: 'Kode' },
|
||||||
|
{ key: 'name', label: 'Nama' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const funcParsed: RecStrFuncUnknown = {
|
||||||
|
name: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return `${recX.firstName} ${recX.middleName || ''} ${recX.lastName || ''}`
|
||||||
|
},
|
||||||
|
identity_number: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
|
||||||
|
return '(TANPA NIK)'
|
||||||
|
}
|
||||||
|
return recX.identity_number
|
||||||
|
},
|
||||||
|
birth_date: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
if (typeof recX.birth_date == 'object' && recX.birth_date) {
|
||||||
|
return (recX.birth_date as Date).toLocaleDateString()
|
||||||
|
} else if (typeof recX.birth_date == 'string') {
|
||||||
|
return (recX.birth_date as string).substring(0, 10)
|
||||||
|
}
|
||||||
|
return recX.birth_date
|
||||||
|
},
|
||||||
|
patient_age: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
return recX.birth_date?.split('T')[0]
|
||||||
|
},
|
||||||
|
gender: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
if (typeof recX?.gender_code !== 'number' && recX?.gender_code !== '') {
|
||||||
|
return 'Tidak Diketahui'
|
||||||
|
}
|
||||||
|
return recX.gender_code
|
||||||
|
},
|
||||||
|
education: (rec: unknown): unknown => {
|
||||||
|
const recX = rec as SmallDetailDto
|
||||||
|
if (typeof recX.education_code == 'number' && recX.education_code >= 0) {
|
||||||
|
return recX.education_code
|
||||||
|
} else if (typeof recX.education_code) {
|
||||||
|
return recX.education_code
|
||||||
|
}
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcComponent: RecStrFuncComponent = {
|
||||||
|
action(rec, idx) {
|
||||||
|
const res: RecComponent = {
|
||||||
|
idx,
|
||||||
|
rec: rec as object,
|
||||||
|
component: action,
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const funcHtml: RecStrFuncUnknown = {
|
||||||
|
patient_address(_rec) {
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cols, funcComponent, funcHtml, funcParsed, header, keys } from './list-cfg'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
data: any[]
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PubBaseDataTable
|
||||||
|
:rows="data"
|
||||||
|
:cols="cols"
|
||||||
|
:header="header"
|
||||||
|
:keys="keys"
|
||||||
|
:func-parsed="funcParsed"
|
||||||
|
:func-html="funcHtml"
|
||||||
|
:func-component="funcComponent"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps<{
|
||||||
|
rec: any
|
||||||
|
idx?: number
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col justify-center">
|
||||||
|
<p class="font-semibold text-sm">{{ props.rec.patient.name }}</p>
|
||||||
|
<p class="text-xs text-muted-foreground">{{ props.rec.patient.mrn }}</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Badge from './badge.vue'
|
||||||
|
import { rowStatus } from './list-cfg'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rec: { status: number }
|
||||||
|
idx?: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const variants = {
|
||||||
|
0: 'error',
|
||||||
|
1: 'warning',
|
||||||
|
2: 'info',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
const statusText = computed(() => {
|
||||||
|
return rowStatus[props.rec.status as keyof typeof rowStatus]
|
||||||
|
})
|
||||||
|
|
||||||
|
const badgeStatus = computed((): 'error' | 'warning' | 'success' | 'info' => {
|
||||||
|
return variants[props.rec.status as keyof typeof variants] ?? 'info'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex">
|
||||||
|
<Badge :status="badgeStatus" :text="statusText" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { cva } from 'class-variance-authority'
|
||||||
|
import { cn } from '~/lib/utils'
|
||||||
|
|
||||||
|
interface BadgeProps {
|
||||||
|
status: 'success' | 'info' | 'warning' | 'error'
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<BadgeProps>()
|
||||||
|
|
||||||
|
const badgeVariants = cva(
|
||||||
|
'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
success: 'rounded-full border-transparent bg-green-500 text-white hover:bg-green-600',
|
||||||
|
info: 'rounded-full border-transparent bg-blue-500 text-white hover:bg-blue-600',
|
||||||
|
warning: 'rounded-full border-transparent bg-yellow-500 text-white hover:bg-yellow-600',
|
||||||
|
error: 'rounded-full border-transparent bg-red-500 text-white hover:bg-red-600',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: 'info',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex">
|
||||||
|
<div :class="cn(badgeVariants({ variant: props.status }))">
|
||||||
|
{{ props.text }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user