276 lines
7.3 KiB
Vue
276 lines
7.3 KiB
Vue
<template>
|
|
<v-dialog v-model="dialogModel" max-width="900px" persistent scrollable>
|
|
<v-card class="dialog-card">
|
|
<v-card-title class="dialog-header">
|
|
<span class="headline-4">{{ isEdit ? 'Edit Klinik' : 'Tambah Klinik' }}</span>
|
|
<v-btn icon variant="text" size="small" class="btn-close" @click="handleClose">
|
|
<v-icon>mdi-close</v-icon>
|
|
</v-btn>
|
|
</v-card-title>
|
|
|
|
<v-divider/>
|
|
|
|
<v-card-text class="dialog-content">
|
|
<v-form ref="formRef">
|
|
<!-- Informasi Dasar -->
|
|
<FormFieldGroup title="Informasi Dasar">
|
|
<v-row dense>
|
|
<v-col cols="4">
|
|
<v-text-field
|
|
v-model="formModel.kode"
|
|
label="Kode"
|
|
variant="outlined"
|
|
density="compact"
|
|
:rules="[v => !!v || 'Kode harus diisi']"
|
|
hide-details="auto"
|
|
placeholder="AN"
|
|
class="mb-3 input-field"
|
|
/>
|
|
<small class="caption-2">2 Huruf</small>
|
|
</v-col>
|
|
<v-col cols="4">
|
|
<v-text-field
|
|
v-model="formModel.nama"
|
|
label="Nama"
|
|
variant="outlined"
|
|
density="compact"
|
|
:rules="[v => !!v || 'Nama harus diisi']"
|
|
hide-details="auto"
|
|
placeholder="Gigi dan Mulut"
|
|
class="mb-3 input-field"
|
|
/>
|
|
</v-col>
|
|
<v-col cols="4">
|
|
<v-text-field
|
|
v-model.number="formModel.shift"
|
|
label="Jumlah Shift"
|
|
type="number"
|
|
variant="outlined"
|
|
density="compact"
|
|
:rules="[v => !!v || 'Shift harus diisi', v => v > 0 || 'Minimal 1']"
|
|
hide-details="auto"
|
|
class="mb-3 input-field"
|
|
@update:model-value="updateShiftCount"
|
|
/>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<v-checkbox
|
|
v-model="formModel.autoShift"
|
|
label="Auto Shift"
|
|
hide-details
|
|
color="#0671E0"
|
|
density="compact"
|
|
class="checkbox-field"
|
|
/>
|
|
</FormFieldGroup>
|
|
|
|
<v-divider class="my-4 divider-section"/>
|
|
|
|
<!-- Konfigurasi Shift & Kuota -->
|
|
<FormFieldGroup title="Konfigurasi Shift & Kuota" icon="mdi-clock-outline">
|
|
<ShiftConfiguration
|
|
:shifts="formModel.jamShiftList"
|
|
@update:shifts="formModel.jamShiftList = $event"
|
|
@remove-shift="removeShift"
|
|
/>
|
|
</FormFieldGroup>
|
|
|
|
<v-divider class="my-4 divider-section"/>
|
|
|
|
<!-- Jadwal Klinik -->
|
|
<FormFieldGroup title="Jadwal Klinik" icon="mdi-calendar-check">
|
|
<DaySelector v-model="formModel.jadwalKlinik" />
|
|
</FormFieldGroup>
|
|
</v-form>
|
|
</v-card-text>
|
|
|
|
<v-divider/>
|
|
|
|
<v-card-actions class="dialog-actions">
|
|
<v-spacer/>
|
|
<v-btn
|
|
variant="outlined"
|
|
class="btn-cancel"
|
|
@click="handleClose"
|
|
>
|
|
<v-icon left size="18">mdi-close</v-icon>
|
|
Batal
|
|
</v-btn>
|
|
<v-btn
|
|
variant="flat"
|
|
class="btn-submit"
|
|
@click="handleSubmit"
|
|
>
|
|
<v-icon left size="18">mdi-content-save</v-icon>
|
|
Simpan
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed } from 'vue';
|
|
import FormFieldGroup from '@/components/common/FormFieldGroup.vue';
|
|
import ShiftConfiguration from '@/components/master/ShiftConfiguration.vue';
|
|
import DaySelector from '@/components/master/DaySelector.vue';
|
|
|
|
const props = defineProps({
|
|
modelValue: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
isEdit: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
formData: {
|
|
type: Object,
|
|
required: true
|
|
}
|
|
});
|
|
|
|
const emit = defineEmits(['update:modelValue', 'update:formData', 'submit', 'close']);
|
|
|
|
const formRef = ref(null);
|
|
|
|
const dialogModel = computed({
|
|
get: () => props.modelValue,
|
|
set: (value) => emit('update:modelValue', value)
|
|
});
|
|
|
|
const formModel = computed({
|
|
get: () => props.formData,
|
|
set: (value) => emit('update:formData', value)
|
|
});
|
|
|
|
const updateShiftCount = (newShiftCount) => {
|
|
const currentCount = formModel.value.jamShiftList.length;
|
|
|
|
if (newShiftCount > currentCount) {
|
|
for (let i = currentCount; i < newShiftCount; i++) {
|
|
let defaultDari = '07:00', defaultSampai = '11:00';
|
|
|
|
if (i === 1) { defaultDari = '13:00'; defaultSampai = '16:00'; }
|
|
else if (i === 2) { defaultDari = '18:00'; defaultSampai = '20:00'; }
|
|
else if (i > 2) {
|
|
const prevShift = formModel.value.jamShiftList[i - 1];
|
|
const [prevHour] = prevShift.sampai.split(':');
|
|
const nextHour = (parseInt(prevHour) + 1) % 24;
|
|
defaultDari = `${String(nextHour).padStart(2, '0')}:00`;
|
|
defaultSampai = `${String((nextHour + 4) % 24).padStart(2, '0')}:00`;
|
|
}
|
|
|
|
formModel.value.jamShiftList.push({ dari: defaultDari, sampai: defaultSampai, kuota: 0 });
|
|
}
|
|
} else if (newShiftCount < currentCount && newShiftCount > 0) {
|
|
formModel.value.jamShiftList = formModel.value.jamShiftList.slice(0, newShiftCount);
|
|
}
|
|
};
|
|
|
|
const removeShift = (index) => {
|
|
if (formModel.value.jamShiftList.length > 1) {
|
|
formModel.value.jamShiftList.splice(index, 1);
|
|
formModel.value.shift = formModel.value.jamShiftList.length;
|
|
}
|
|
};
|
|
|
|
const handleClose = () => {
|
|
emit('close');
|
|
};
|
|
|
|
const handleSubmit = async () => {
|
|
const { valid } = await formRef.value.validate();
|
|
if (valid) {
|
|
emit('submit', formModel.value);
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
$neutral-100: #FFFFFF;
|
|
$neutral-300: #F5F7FA;
|
|
$neutral-400: #E5F7FA;
|
|
$neutral-600: #89939E;
|
|
$neutral-700: #717171;
|
|
$neutral-800: #4D4D4D;
|
|
$secondary-600: #0671E0;
|
|
$secondary-700: #0053AD;
|
|
$font-family-base: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
$font-weight-semibold: 600;
|
|
|
|
.dialog-card {
|
|
font-family: $font-family-base;
|
|
}
|
|
|
|
.dialog-header {
|
|
background: linear-gradient(135deg, $secondary-600 0%, $secondary-700 100%);
|
|
color: $neutral-100;
|
|
padding: 20px 24px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.headline-4 {
|
|
font-size: 20px;
|
|
line-height: 28px;
|
|
font-weight: $font-weight-semibold;
|
|
margin: 0;
|
|
}
|
|
|
|
.btn-close {
|
|
color: $neutral-100 !important;
|
|
}
|
|
|
|
.dialog-content {
|
|
padding: 24px !important;
|
|
background: $neutral-300;
|
|
}
|
|
|
|
.dialog-actions {
|
|
padding: 16px 24px;
|
|
background: $neutral-300;
|
|
}
|
|
|
|
.caption-2 {
|
|
font-size: 12px;
|
|
line-height: 16px;
|
|
color: $neutral-700;
|
|
}
|
|
|
|
.input-field {
|
|
font-size: 14px;
|
|
line-height: 20px;
|
|
}
|
|
|
|
.checkbox-field {
|
|
font-size: 14px;
|
|
line-height: 20px;
|
|
}
|
|
|
|
.divider-section {
|
|
border-color: $neutral-400 !important;
|
|
}
|
|
|
|
.btn-cancel {
|
|
border-color: $neutral-600 !important;
|
|
color: $neutral-800 !important;
|
|
text-transform: none;
|
|
font-weight: $font-weight-semibold;
|
|
font-size: 16px;
|
|
line-height: 24px;
|
|
min-width: 100px;
|
|
}
|
|
|
|
.btn-submit {
|
|
background-color: $secondary-600 !important;
|
|
color: $neutral-100 !important;
|
|
text-transform: none;
|
|
font-weight: $font-weight-semibold;
|
|
font-size: 16px;
|
|
line-height: 24px;
|
|
min-width: 100px;
|
|
}
|
|
</style> |