Merge branch 'dev' of https://github.com/dikstub-rssa/simrs-fe into fe-specialist-intern-35

This commit is contained in:
Abizrh
2025-09-15 19:18:26 +07:00
622 changed files with 35907 additions and 1 deletions
+30
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
API_ORIGIN=
+9
View File
@@ -0,0 +1,9 @@
{
"useTabs": false,
"tabWidth": 2,
"singleQuote": true,
"trailingComma": "all",
"printWidth": 120,
"semi": false,
"plugins": ["prettier-plugin-tailwindcss"]
}
+15
View File
@@ -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}"
}
]
}
+75
View File
@@ -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.
+108 -1
View File
@@ -2,4 +2,111 @@
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
View File
@@ -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>
+340
View File
@@ -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 */
+74
View File
@@ -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>
+125
View File
@@ -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>
+86
View File
@@ -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 '-'
},
}
+35
View File
@@ -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>
+48
View File
@@ -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>
+114
View File
@@ -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 '-'
},
}
+19
View File
@@ -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>
+109
View File
@@ -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 '-'
},
}
+19
View File
@@ -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>
+148
View File
@@ -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>
+51
View File
@@ -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> = {}
+38
View File
@@ -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 '-'
},
}
+36
View File
@@ -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>
+46
View File
@@ -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 '-'
},
}
+19
View File
@@ -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>
+68
View File
@@ -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>
+46
View File
@@ -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 '-'
},
}
+19
View File
@@ -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>
View File
View File
+29
View File
@@ -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>
+114
View File
@@ -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 '-'
},
}
+19
View File
@@ -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>
+67
View File
@@ -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 '-'
// },
}
+19
View File
@@ -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>
+31
View File
@@ -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>
+114
View File
@@ -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 '-'
},
}
+19
View File
@@ -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>
View File
View File
+29
View File
@@ -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>
+114
View File
@@ -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 '-'
},
}
+19
View File
@@ -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>
+43
View File
@@ -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>
+131
View File
@@ -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 '-'
},
}
+19
View File
@@ -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>
+340
View File
@@ -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>
+114
View File
@@ -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 '-'
},
}
+19
View File
@@ -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>
+36
View File
@@ -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