feat: change UI language into english from indonesia
This commit is contained in:
parent
7633bd25e3
commit
520099ca8b
|
|
@ -204,7 +204,7 @@ describe('AuditController', () => {
|
||||||
const result = controller.createAuditTrail();
|
const result = controller.createAuditTrail();
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
message: 'Proses audit trail dijalankan',
|
message: 'Audit trail process started',
|
||||||
status: 'STARTED',
|
status: 'STARTED',
|
||||||
});
|
});
|
||||||
expect(mockAuditService.storeAuditTrail).toHaveBeenCalled();
|
expect(mockAuditService.storeAuditTrail).toHaveBeenCalled();
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,6 @@ export class AuditController {
|
||||||
@UseGuards(AuthGuard)
|
@UseGuards(AuthGuard)
|
||||||
createAuditTrail() {
|
createAuditTrail() {
|
||||||
this.auditService.storeAuditTrail();
|
this.auditService.storeAuditTrail();
|
||||||
return { message: 'Proses audit trail dijalankan', status: 'STARTED' };
|
return { message: 'Audit trail process started', status: 'STARTED' };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ describe('AuthController', () => {
|
||||||
|
|
||||||
const result = controller.logout(mockResponse as any);
|
const result = controller.logout(mockResponse as any);
|
||||||
|
|
||||||
expect(result).toEqual({ message: 'Logout berhasil' });
|
expect(result).toEqual({ message: 'Logout successful' });
|
||||||
expect(mockResponse.clearCookie).toHaveBeenCalledWith('access_token', {
|
expect(mockResponse.clearCookie).toHaveBeenCalledWith('access_token', {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: false,
|
secure: false,
|
||||||
|
|
@ -195,7 +195,7 @@ describe('AuthController', () => {
|
||||||
|
|
||||||
const result = controller.logout(mockResponse as any);
|
const result = controller.logout(mockResponse as any);
|
||||||
|
|
||||||
expect(result).toEqual({ message: 'Logout berhasil' });
|
expect(result).toEqual({ message: 'Logout successful' });
|
||||||
expect(mockResponse.clearCookie).toHaveBeenCalledWith('access_token', {
|
expect(mockResponse.clearCookie).toHaveBeenCalledWith('access_token', {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: true,
|
secure: true,
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,6 @@ export class AuthController {
|
||||||
sameSite: 'strict',
|
sameSite: 'strict',
|
||||||
});
|
});
|
||||||
|
|
||||||
return { message: 'Logout berhasil' };
|
return { message: 'Logout successful' };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ export class AuthService {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!user || !(await bcrypt.compare(password, user.password_hash))) {
|
if (!user || !(await bcrypt.compare(password, user.password_hash))) {
|
||||||
throw new UnauthorizedException('Username atau password salah');
|
throw new UnauthorizedException('Wrong username or password');
|
||||||
}
|
}
|
||||||
|
|
||||||
const csrfToken = crypto.randomBytes(32).toString('hex');
|
const csrfToken = crypto.randomBytes(32).toString('hex');
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,13 @@ export enum UserRole {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AuthDto {
|
export class AuthDto {
|
||||||
@IsNotEmpty({ message: 'Username wajib diisi' })
|
@IsNotEmpty({ message: 'Username is required' })
|
||||||
@IsString({ message: 'Username harus berupa string' })
|
@IsString({ message: 'Username must be a string' })
|
||||||
@Length(1, 100, { message: 'Username maksimal 100 karakter' })
|
@Length(1, 100, { message: 'Username must be at most 100 characters' })
|
||||||
username: string;
|
username: string;
|
||||||
|
|
||||||
@IsNotEmpty({ message: 'Password wajib diisi' })
|
@IsNotEmpty({ message: 'Password is required' })
|
||||||
@IsString({ message: 'Password harus berupa string' })
|
@IsString({ message: 'Password must be a string' })
|
||||||
@Length(6, undefined, { message: 'Password minimal 6 karakter' })
|
@Length(6, undefined, { message: 'Password must be at least 6 characters' })
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,26 +9,26 @@ import { Expose, Transform } from 'class-transformer';
|
||||||
import { UserRole } from './auth.dto';
|
import { UserRole } from './auth.dto';
|
||||||
|
|
||||||
export class CreateUserDto {
|
export class CreateUserDto {
|
||||||
@IsNotEmpty({ message: 'Nama lengkap wajib diisi' })
|
@IsNotEmpty({ message: 'Full name is required' })
|
||||||
@IsString({ message: 'Nama lengkap harus berupa string' })
|
@IsString({ message: 'Full name must be a string' })
|
||||||
@Length(1, 255, { message: 'Nama lengkap maksimal 255 karakter' })
|
@Length(1, 255, { message: 'Full name must be at most 255 characters' })
|
||||||
nama_lengkap: string;
|
nama_lengkap: string;
|
||||||
|
|
||||||
@IsNotEmpty({ message: 'Username wajib diisi' })
|
@IsNotEmpty({ message: 'Username is required' })
|
||||||
@IsString({ message: 'Username harus berupa string' })
|
@IsString({ message: 'Username must be a string' })
|
||||||
@Length(1, 100, { message: 'Username maksimal 100 karakter' })
|
@Length(1, 100, { message: 'Username must be at most 100 characters' })
|
||||||
username: string;
|
username: string;
|
||||||
|
|
||||||
@IsNotEmpty({ message: 'Password wajib diisi' })
|
@IsNotEmpty({ message: 'Password is required' })
|
||||||
@IsString({ message: 'Password harus berupa string' })
|
@IsString({ message: 'Password must be a string' })
|
||||||
@Length(6, 100, {
|
@Length(6, 100, {
|
||||||
message: 'Password minimal 6 karakter dan maksimal 100 karakter',
|
message: 'Password must be between 6 and 100 characters',
|
||||||
})
|
})
|
||||||
password: string;
|
password: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString({ message: 'Role harus berupa string' })
|
@IsString({ message: 'Role must be a string' })
|
||||||
@IsEnum(UserRole, { message: 'Role harus "admin" atau "user"' })
|
@IsEnum(UserRole, { message: 'Role must be "admin" or "user"' })
|
||||||
role?: UserRole;
|
role?: UserRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ describe('FabricService', () => {
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
service.storeLog('log-1', 'CREATE', 'user-1', '{}'),
|
service.storeLog('log-1', 'CREATE', 'user-1', '{}'),
|
||||||
).rejects.toThrow('Gagal menyimpan log ke blockchain');
|
).rejects.toThrow('Failed to store log to blockchain');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not validate empty id (NO VALIDATION)', async () => {
|
it('should not validate empty id (NO VALIDATION)', async () => {
|
||||||
|
|
@ -273,7 +273,7 @@ describe('FabricService', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(service.getLogById('non-existent')).rejects.toThrow(
|
await expect(service.getLogById('non-existent')).rejects.toThrow(
|
||||||
'Gagal mengambil log dari blockchain',
|
'Failed to retrieve log from blockchain',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -325,7 +325,7 @@ describe('FabricService', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(service.getAllLogs()).rejects.toThrow(
|
await expect(service.getAllLogs()).rejects.toThrow(
|
||||||
'Gagal mengambil semua log dari blockchain',
|
'Failed to retrieve all logs from blockchain',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -370,7 +370,7 @@ describe('FabricService', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(service.getLogsWithPagination(10, '')).rejects.toThrow(
|
await expect(service.getLogsWithPagination(10, '')).rejects.toThrow(
|
||||||
'Gagal mengambil log dengan paginasi dari blockchain',
|
'Failed to retrieve logs with pagination from blockchain',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ export class FabricService implements OnModuleInit, OnApplicationShutdown {
|
||||||
const message = error instanceof Error ? error.message : 'Unknown error';
|
const message = error instanceof Error ? error.message : 'Unknown error';
|
||||||
this.logger.error(`Failed to store log: ${message}`);
|
this.logger.error(`Failed to store log: ${message}`);
|
||||||
throw new InternalServerErrorException(
|
throw new InternalServerErrorException(
|
||||||
'Gagal menyimpan log ke blockchain',
|
'Failed to store log to blockchain',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -78,7 +78,7 @@ export class FabricService implements OnModuleInit, OnApplicationShutdown {
|
||||||
const message = error instanceof Error ? error.message : 'Unknown error';
|
const message = error instanceof Error ? error.message : 'Unknown error';
|
||||||
this.logger.error(`Failed to get log by ID: ${message}`);
|
this.logger.error(`Failed to get log by ID: ${message}`);
|
||||||
throw new InternalServerErrorException(
|
throw new InternalServerErrorException(
|
||||||
'Gagal mengambil log dari blockchain',
|
'Failed to retrieve log from blockchain',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -91,7 +91,7 @@ export class FabricService implements OnModuleInit, OnApplicationShutdown {
|
||||||
const message = error instanceof Error ? error.message : 'Unknown error';
|
const message = error instanceof Error ? error.message : 'Unknown error';
|
||||||
this.logger.error(`Failed to get all logs: ${message}`);
|
this.logger.error(`Failed to get all logs: ${message}`);
|
||||||
throw new InternalServerErrorException(
|
throw new InternalServerErrorException(
|
||||||
'Gagal mengambil semua log dari blockchain',
|
'Failed to retrieve all logs from blockchain',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -106,7 +106,7 @@ export class FabricService implements OnModuleInit, OnApplicationShutdown {
|
||||||
const message = error instanceof Error ? error.message : 'Unknown error';
|
const message = error instanceof Error ? error.message : 'Unknown error';
|
||||||
this.logger.error(`Failed to get logs with pagination: ${message}`);
|
this.logger.error(`Failed to get logs with pagination: ${message}`);
|
||||||
throw new InternalServerErrorException(
|
throw new InternalServerErrorException(
|
||||||
'Gagal mengambil log dengan paginasi dari blockchain',
|
'Failed to retrieve logs with pagination from blockchain',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import { IsString, IsNotEmpty, Length, IsEnum } from 'class-validator';
|
import { IsString, IsNotEmpty, Length, IsEnum } from 'class-validator';
|
||||||
|
|
||||||
export class StoreLogDto {
|
export class StoreLogDto {
|
||||||
@IsNotEmpty({ message: 'ID wajib diisi' })
|
@IsNotEmpty({ message: 'ID is required' })
|
||||||
@IsString({ message: 'ID harus berupa string' })
|
@IsString({ message: 'ID must be a string' })
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
@IsNotEmpty({ message: 'Event wajib diisi' })
|
@IsNotEmpty({ message: 'Event is required' })
|
||||||
@IsString({ message: 'Event harus berupa string' })
|
@IsString({ message: 'Event must be a string' })
|
||||||
@IsEnum(
|
@IsEnum(
|
||||||
[
|
[
|
||||||
'tindakan_dokter_created',
|
'tindakan_dokter_created',
|
||||||
|
|
@ -20,17 +20,17 @@ export class StoreLogDto {
|
||||||
'rekam_medis_deleted',
|
'rekam_medis_deleted',
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
message: 'Event tidak valid',
|
message: 'Invalid event',
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@Length(1, 100, { message: 'Event maksimal 100 karakter' })
|
@Length(1, 100, { message: 'Event must be at most 100 characters' })
|
||||||
event: string;
|
event: string;
|
||||||
|
|
||||||
@IsNotEmpty({ message: 'User ID wajib diisi' })
|
@IsNotEmpty({ message: 'User ID is required' })
|
||||||
@IsString({ message: 'User ID harus berupa string' })
|
@IsString({ message: 'User ID must be a string' })
|
||||||
user_id: string;
|
user_id: string;
|
||||||
|
|
||||||
@IsNotEmpty({ message: 'Payload wajib diisi' })
|
@IsNotEmpty({ message: 'Payload is required' })
|
||||||
@IsString({ message: 'Payload harus berupa string' })
|
@IsString({ message: 'Payload must be a string' })
|
||||||
payload: string;
|
payload: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ export class ObatService {
|
||||||
|
|
||||||
async createObat(dto: CreateObatDto, user: ActiveUserPayload) {
|
async createObat(dto: CreateObatDto, user: ActiveUserPayload) {
|
||||||
if (!(await this.isIdVisitExists(dto.id_visit))) {
|
if (!(await this.isIdVisitExists(dto.id_visit))) {
|
||||||
throw new BadRequestException(`ID Visit ${dto.id_visit} tidak ditemukan`);
|
throw new BadRequestException(`Visit ID ${dto.id_visit} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -157,7 +157,7 @@ export class ObatService {
|
||||||
|
|
||||||
async createObatToDBAndBlockchain(dto: CreateObatDto, userId: number) {
|
async createObatToDBAndBlockchain(dto: CreateObatDto, userId: number) {
|
||||||
if (!(await this.isIdVisitExists(dto.id_visit))) {
|
if (!(await this.isIdVisitExists(dto.id_visit))) {
|
||||||
throw new BadRequestException(`Visit with id ${dto.id_visit} not found`);
|
throw new BadRequestException(`Visit id ${dto.id_visit} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -200,11 +200,11 @@ export class ObatService {
|
||||||
const obatId = Number(id);
|
const obatId = Number(id);
|
||||||
|
|
||||||
if (isNaN(obatId)) {
|
if (isNaN(obatId)) {
|
||||||
throw new BadRequestException('ID obat tidak valid');
|
throw new BadRequestException('ID medicine not valid');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(await this.getObatById(obatId))) {
|
if (!(await this.getObatById(obatId))) {
|
||||||
throw new BadRequestException(`Obat with id ${obatId} not found`);
|
throw new BadRequestException(`Medicine with id ${obatId} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -244,15 +244,13 @@ export class ObatService {
|
||||||
const obatId = Number(id);
|
const obatId = Number(id);
|
||||||
|
|
||||||
if (isNaN(obatId)) {
|
if (isNaN(obatId)) {
|
||||||
throw new BadRequestException('ID obat tidak valid');
|
throw new BadRequestException('Medicine ID not valid');
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingObat = await this.getObatById(obatId);
|
const existingObat = await this.getObatById(obatId);
|
||||||
|
|
||||||
if (!existingObat) {
|
if (!existingObat) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(`Medicine with ID ${obatId} not found`);
|
||||||
`Pemberian obat dengan ID ${obatId} tidak ditemukan`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasUpdates =
|
const hasUpdates =
|
||||||
|
|
@ -261,7 +259,7 @@ export class ObatService {
|
||||||
dto.aturan_pakai !== existingObat.aturan_pakai;
|
dto.aturan_pakai !== existingObat.aturan_pakai;
|
||||||
|
|
||||||
if (!hasUpdates) {
|
if (!hasUpdates) {
|
||||||
throw new BadRequestException('Tidak ada perubahan data obat');
|
throw new BadRequestException('No changes in medicine data detected');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -325,12 +323,12 @@ export class ObatService {
|
||||||
const obatId = Number(id);
|
const obatId = Number(id);
|
||||||
|
|
||||||
if (isNaN(obatId)) {
|
if (isNaN(obatId)) {
|
||||||
throw new BadRequestException('ID obat tidak valid');
|
throw new BadRequestException('Medicine ID not valid');
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingObat = await this.getObatById(obatId);
|
const existingObat = await this.getObatById(obatId);
|
||||||
if (!existingObat) {
|
if (!existingObat) {
|
||||||
throw new BadRequestException(`Obat dengan ID ${obatId} tidak ditemukan`);
|
throw new BadRequestException(`Medicine with ID ${obatId} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -14,27 +14,29 @@ import {
|
||||||
import { Transform } from 'class-transformer';
|
import { Transform } from 'class-transformer';
|
||||||
|
|
||||||
export class CreateRekamMedisDto {
|
export class CreateRekamMedisDto {
|
||||||
@IsNotEmpty({ message: 'Nomor rekam medis (no_rm) wajib diisi' })
|
@IsNotEmpty({ message: 'Medical record number (no_rm) is required' })
|
||||||
@IsString()
|
@IsString()
|
||||||
@Length(1, 20, { message: 'Nomor rekam medis maksimal 20 karakter' })
|
@Length(1, 20, {
|
||||||
|
message: 'Medical record number must be at most 20 characters',
|
||||||
|
})
|
||||||
no_rm: string;
|
no_rm: string;
|
||||||
|
|
||||||
@IsNotEmpty({ message: 'Nama pasien wajib diisi' })
|
@IsNotEmpty({ message: 'Patient name is required' })
|
||||||
@IsString()
|
@IsString()
|
||||||
@Length(1, 100, { message: 'Nama pasien maksimal 100 karakter' })
|
@Length(1, 100, { message: 'Patient name must be at most 100 characters' })
|
||||||
nama_pasien: string;
|
nama_pasien: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsInt({ message: 'Umur harus berupa angka bulat' })
|
@IsInt({ message: 'Age must be an integer' })
|
||||||
@Min(0, { message: 'Umur tidak boleh negatif' })
|
@Min(0, { message: 'Age cannot be negative' })
|
||||||
@Max(150, { message: 'Umur tidak valid' })
|
@Max(150, { message: 'Age is not valid' })
|
||||||
@Transform(({ value }) => (value ? parseInt(value) : null))
|
@Transform(({ value }) => (value ? parseInt(value) : null))
|
||||||
umur?: number;
|
umur?: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsIn(['L', 'P', 'l', 'p'], {
|
@IsIn(['L', 'P', 'l', 'p'], {
|
||||||
message: 'Jenis kelamin harus "L" (Laki-laki) atau "P" (Perempuan)',
|
message: 'Gender must be "L" (Male) or "P" (Female)',
|
||||||
})
|
})
|
||||||
@Transform(({ value }) => value?.toUpperCase())
|
@Transform(({ value }) => value?.toUpperCase())
|
||||||
jenis_kelamin?: string;
|
jenis_kelamin?: string;
|
||||||
|
|
@ -42,7 +44,7 @@ export class CreateRekamMedisDto {
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsIn(['A', 'B', 'AB', 'O', '-'], {
|
@IsIn(['A', 'B', 'AB', 'O', '-'], {
|
||||||
message: 'Golongan darah harus A, B, AB, O, atau -',
|
message: 'Blood type must be A, B, AB, O, or -',
|
||||||
})
|
})
|
||||||
@Length(1, 2)
|
@Length(1, 2)
|
||||||
gol_darah?: string;
|
gol_darah?: string;
|
||||||
|
|
@ -70,37 +72,37 @@ export class CreateRekamMedisDto {
|
||||||
anamnese?: string;
|
anamnese?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsInt({ message: 'Tekanan darah sistolik harus berupa angka bulat' })
|
@IsInt({ message: 'Systolic blood pressure must be an integer' })
|
||||||
@Transform(({ value }) => (value ? parseInt(value) : null))
|
@Transform(({ value }) => (value ? parseInt(value) : null))
|
||||||
sistolik?: number;
|
sistolik?: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsInt({ message: 'Tekanan darah diastolik harus berupa angka bulat' })
|
@IsInt({ message: 'Diastolic blood pressure must be an integer' })
|
||||||
@Transform(({ value }) => (value ? parseInt(value) : null))
|
@Transform(({ value }) => (value ? parseInt(value) : null))
|
||||||
diastolik?: number;
|
diastolik?: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsInt({ message: 'Nadi harus berupa angka bulat' })
|
@IsInt({ message: 'Pulse must be an integer' })
|
||||||
@Transform(({ value }) => (value ? parseInt(value) : null))
|
@Transform(({ value }) => (value ? parseInt(value) : null))
|
||||||
nadi?: number;
|
nadi?: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsNumber({}, { message: 'Suhu harus berupa angka' })
|
@IsNumber({}, { message: 'Temperature must be a number' })
|
||||||
@Transform(({ value }) => (value ? parseFloat(value) : null))
|
@Transform(({ value }) => (value ? parseFloat(value) : null))
|
||||||
suhu?: number;
|
suhu?: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsInt({ message: 'Pernapasan harus berupa angka bulat' })
|
@IsInt({ message: 'Respiration must be an integer' })
|
||||||
@Transform(({ value }) => (value ? parseInt(value) : null))
|
@Transform(({ value }) => (value ? parseInt(value) : null))
|
||||||
nafas?: number;
|
nafas?: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsNumber({}, { message: 'Tinggi badan harus berupa angka' })
|
@IsNumber({}, { message: 'Height must be a number' })
|
||||||
@Transform(({ value }) => (value ? parseFloat(value) : null))
|
@Transform(({ value }) => (value ? parseFloat(value) : null))
|
||||||
tinggi_badan?: number;
|
tinggi_badan?: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsNumber({}, { message: 'Berat badan harus berupa angka' })
|
@IsNumber({}, { message: 'Weight must be a number' })
|
||||||
@Transform(({ value }) => (value ? parseFloat(value) : null))
|
@Transform(({ value }) => (value ? parseFloat(value) : null))
|
||||||
berat_badan?: number;
|
berat_badan?: number;
|
||||||
|
|
||||||
|
|
@ -114,6 +116,6 @@ export class CreateRekamMedisDto {
|
||||||
tindak_lanjut?: string;
|
tindak_lanjut?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsDateString({}, { message: 'Waktu visit harus berupa tanggal yang valid' })
|
@IsDateString({}, { message: 'Visit time must be a valid date' })
|
||||||
waktu_visit?: string;
|
waktu_visit?: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
import { IsEnum, IsNumber, IsString } from 'class-validator';
|
import { IsEnum, IsNumber, IsString } from 'class-validator';
|
||||||
|
|
||||||
export class PayloadRekamMedisDto {
|
export class PayloadRekamMedisDto {
|
||||||
@IsNumber({}, { message: 'ID dokter harus berupa angka' })
|
@IsNumber({}, { message: 'Doctor ID must be a number' })
|
||||||
dokter_id: number;
|
dokter_id: number;
|
||||||
|
|
||||||
@IsString({ message: 'ID kunjungan harus berupa string' })
|
@IsString({ message: 'Visit ID must be a string' })
|
||||||
visit_id: string;
|
visit_id: string;
|
||||||
|
|
||||||
@IsEnum({}, { message: 'Anamnese harus berupa enum' })
|
@IsEnum({}, { message: 'Anamnese must be an enum' })
|
||||||
anamnese: string;
|
anamnese: string;
|
||||||
|
|
||||||
@IsEnum({}, { message: 'Jenis kasus harus berupa enum' })
|
@IsEnum({}, { message: 'Case type must be an enum' })
|
||||||
jenis_kasus: string;
|
jenis_kasus: string;
|
||||||
|
|
||||||
@IsEnum({}, { message: 'Tindak lanjut harus berupa enum' })
|
@IsEnum({}, { message: 'Follow-up must be an enum' })
|
||||||
tindak_lanjut: string;
|
tindak_lanjut: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ export class TindakanDokterController {
|
||||||
skip,
|
skip,
|
||||||
page,
|
page,
|
||||||
orderBy: orderBy ? { [orderBy]: order || 'asc' } : undefined,
|
orderBy: orderBy ? { [orderBy]: order || 'asc' } : undefined,
|
||||||
|
order,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ export class TindakanDokterService {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!visitExists) {
|
if (!visitExists) {
|
||||||
throw new BadRequestException(`ID Visit ${dto.id_visit} tidak ditemukan`);
|
throw new BadRequestException(`Visit ID ${dto.id_visit} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await this.prisma.validation_queue.create({
|
const response = await this.prisma.validation_queue.create({
|
||||||
|
|
@ -172,7 +172,7 @@ export class TindakanDokterService {
|
||||||
});
|
});
|
||||||
return newTindakan;
|
return newTindakan;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error creating Rekam Medis:', error);
|
console.error('Error creating Doctor Action:', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -181,7 +181,7 @@ export class TindakanDokterService {
|
||||||
const tindakanId = Number(id);
|
const tindakanId = Number(id);
|
||||||
|
|
||||||
if (Number.isNaN(tindakanId)) {
|
if (Number.isNaN(tindakanId)) {
|
||||||
throw new BadRequestException('ID tindakan tidak valid');
|
throw new BadRequestException('Invalid action ID');
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.prisma.pemberian_tindakan.findUnique({
|
return this.prisma.pemberian_tindakan.findUnique({
|
||||||
|
|
@ -197,15 +197,13 @@ export class TindakanDokterService {
|
||||||
const tindakanId = Number(id);
|
const tindakanId = Number(id);
|
||||||
|
|
||||||
if (Number.isNaN(tindakanId)) {
|
if (Number.isNaN(tindakanId)) {
|
||||||
throw new BadRequestException('ID tindakan tidak valid');
|
throw new BadRequestException('Invalid doctor action ID');
|
||||||
}
|
}
|
||||||
|
|
||||||
const existing = await this.getTindakanDokterById(tindakanId);
|
const existing = await this.getTindakanDokterById(tindakanId);
|
||||||
|
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(`Doctor Action with ID ${id} not found`);
|
||||||
`Tindakan dokter dengan ID ${id} tidak ditemukan`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasUpdates =
|
const hasUpdates =
|
||||||
|
|
@ -215,7 +213,7 @@ export class TindakanDokterService {
|
||||||
dto.kelompok_tindakan !== existing.kelompok_tindakan;
|
dto.kelompok_tindakan !== existing.kelompok_tindakan;
|
||||||
|
|
||||||
if (!hasUpdates) {
|
if (!hasUpdates) {
|
||||||
throw new BadRequestException('Tidak ada data tindakan yang diubah');
|
throw new BadRequestException("Doctor action data hasn't been changed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dto.id_visit) {
|
if (dto.id_visit) {
|
||||||
|
|
@ -224,9 +222,7 @@ export class TindakanDokterService {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!visitExists) {
|
if (!visitExists) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(`Visit ID ${dto.id_visit} not found`);
|
||||||
`ID Visit ${dto.id_visit} tidak ditemukan`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -276,7 +272,7 @@ export class TindakanDokterService {
|
||||||
});
|
});
|
||||||
return updatedTindakan;
|
return updatedTindakan;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error updating Tindakan Dokter:', error);
|
console.error('Error updating Doctor Action:', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -285,7 +281,7 @@ export class TindakanDokterService {
|
||||||
const tindakanId = parseInt(id, 10);
|
const tindakanId = parseInt(id, 10);
|
||||||
|
|
||||||
if (Number.isNaN(tindakanId)) {
|
if (Number.isNaN(tindakanId)) {
|
||||||
throw new BadRequestException('ID tindakan tidak valid');
|
throw new BadRequestException('Invalid action ID');
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentData = await this.prisma.pemberian_tindakan.findUnique({
|
const currentData = await this.prisma.pemberian_tindakan.findUnique({
|
||||||
|
|
@ -293,9 +289,7 @@ export class TindakanDokterService {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!currentData) {
|
if (!currentData) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(`Doctor action with ID ${id} not found`);
|
||||||
`Tindakan dokter dengan ID ${id} tidak ditemukan`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const idLog = `TINDAKAN_${id}`;
|
const idLog = `TINDAKAN_${id}`;
|
||||||
|
|
@ -330,15 +324,13 @@ export class TindakanDokterService {
|
||||||
const tindakanId = Number(id);
|
const tindakanId = Number(id);
|
||||||
|
|
||||||
if (Number.isNaN(tindakanId)) {
|
if (Number.isNaN(tindakanId)) {
|
||||||
throw new BadRequestException('ID tindakan tidak valid');
|
throw new BadRequestException('Invalid action ID');
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingTindakan = await this.getTindakanDokterById(tindakanId);
|
const existingTindakan = await this.getTindakanDokterById(tindakanId);
|
||||||
|
|
||||||
if (!existingTindakan) {
|
if (!existingTindakan) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(`Doctor action with ID ${id} not found`);
|
||||||
`Tindakan dokter dengan ID ${id} tidak ditemukan`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -368,7 +360,7 @@ export class TindakanDokterService {
|
||||||
|
|
||||||
return validationQueue;
|
return validationQueue;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error deleting Tindakan Dokter:', error);
|
console.error('Error deleting Doctor Action:', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -376,14 +368,14 @@ export class TindakanDokterService {
|
||||||
async deleteTindakanDokterFromDBAndBlockchain(id: number, userId: number) {
|
async deleteTindakanDokterFromDBAndBlockchain(id: number, userId: number) {
|
||||||
const tindakanId = Number(id);
|
const tindakanId = Number(id);
|
||||||
if (Number.isNaN(tindakanId)) {
|
if (Number.isNaN(tindakanId)) {
|
||||||
throw new BadRequestException('ID tindakan tidak valid');
|
throw new BadRequestException('Invalid action ID');
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingTindakan = await this.getTindakanDokterById(tindakanId);
|
const existingTindakan = await this.getTindakanDokterById(tindakanId);
|
||||||
|
|
||||||
if (!existingTindakan) {
|
if (!existingTindakan) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
`Tindakan dokter dengan ID ${tindakanId} tidak ditemukan`,
|
`Doctor action with ID ${tindakanId} not found`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -410,7 +402,7 @@ export class TindakanDokterService {
|
||||||
});
|
});
|
||||||
return deletedTindakan;
|
return deletedTindakan;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error deleting Tindakan Dokter:', error);
|
console.error('Error deleting Doctor Action:', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ const handleDeleteCancel = () => {
|
||||||
>
|
>
|
||||||
{{ column.label }}
|
{{ column.label }}
|
||||||
</th>
|
</th>
|
||||||
<th v-if="isAksi" class="text-dark">Aksi</th>
|
<th v-if="isAksi" class="text-dark">Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
@ -112,7 +112,7 @@ const handleDeleteCancel = () => {
|
||||||
d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"
|
d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<p>{{ emptyMessage || "Tidak ada data" }}</p>
|
<p>{{ emptyMessage || "No data available" }}</p>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
@ -196,7 +196,7 @@ const handleDeleteCancel = () => {
|
||||||
? 'tooltip tooltip-right flex items-center justify-center'
|
? 'tooltip tooltip-right flex items-center justify-center'
|
||||||
: '',
|
: '',
|
||||||
]"
|
]"
|
||||||
data-tip="Data ini sedang dalam proses validasi untuk dihapus"
|
data-tip="This data is currently undergoing validation for deletion"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
:class="[
|
:class="[
|
||||||
|
|
@ -235,7 +235,7 @@ const handleDeleteCancel = () => {
|
||||||
? 'tooltip tooltip-right flex items-center'
|
? 'tooltip tooltip-right flex items-center'
|
||||||
: '',
|
: '',
|
||||||
]"
|
]"
|
||||||
data-tip="Data ini sedang dalam proses validasi untuk dihapus"
|
data-tip="This data is currently undergoing validation for deletion"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
:class="[
|
:class="[
|
||||||
|
|
@ -346,16 +346,16 @@ const handleDeleteCancel = () => {
|
||||||
|
|
||||||
<DialogConfirm
|
<DialogConfirm
|
||||||
ref="deleteDialogRef"
|
ref="deleteDialogRef"
|
||||||
title="Hapus Data"
|
title="Delete Data"
|
||||||
:message="
|
:message="
|
||||||
pendingDeleteItem?.id
|
pendingDeleteItem?.id
|
||||||
? `Apakah Anda yakin ingin menghapus item dengan ID ${pendingDeleteItem.id}?`
|
? `Are you sure you want to delete item with ID ${pendingDeleteItem.id}?`
|
||||||
: pendingDeleteItem?.id_visit
|
: pendingDeleteItem?.id_visit
|
||||||
? `Apakah Anda yakin ingin menghapus item dengan ID Visit ${pendingDeleteItem?.id_visit}?`
|
? `Are you sure you want to delete item with Visit ID ${pendingDeleteItem?.id_visit}?`
|
||||||
: 'Apakah Anda yakin ingin menghapus item ini?'
|
: 'Are you sure you want to delete this item?'
|
||||||
"
|
"
|
||||||
confirm-text="Hapus"
|
confirm-text="Delete"
|
||||||
cancel-text="Batal"
|
cancel-text="Cancel"
|
||||||
@confirm="handleDeleteConfirm"
|
@confirm="handleDeleteConfirm"
|
||||||
@cancel="handleDeleteCancel"
|
@cancel="handleDeleteCancel"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ const dateTime = ref(new Date());
|
||||||
let clockInterval: number;
|
let clockInterval: number;
|
||||||
|
|
||||||
const formattedDate = computed(() =>
|
const formattedDate = computed(() =>
|
||||||
dateTime.value.toLocaleDateString("id-ID", {
|
dateTime.value.toLocaleDateString("en-US", {
|
||||||
day: "2-digit",
|
day: "2-digit",
|
||||||
month: "long",
|
month: "long",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
|
|
|
||||||
|
|
@ -39,15 +39,14 @@ const handlePageChange = (page: number) => {
|
||||||
<div>
|
<div>
|
||||||
<!-- Pagination Info -->
|
<!-- Pagination Info -->
|
||||||
<div class="text-sm text-gray-600 px-4 py-4">
|
<div class="text-sm text-gray-600 px-4 py-4">
|
||||||
Menampilkan data {{ startIndex }} - {{ endIndex }} dari
|
Showing data {{ startIndex }} - {{ endIndex }} from {{ totalCount }} items
|
||||||
{{ totalCount }} data
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Pagination Controls -->
|
<!-- Pagination Controls -->
|
||||||
<div class="flex justify-between items-center px-4 pb-4">
|
<div class="flex justify-between items-center px-4 pb-4">
|
||||||
<!-- Items per page selector -->
|
<!-- Items per page selector -->
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<span class="text-xs text-gray-600">Data per halaman:</span>
|
<span class="text-xs text-gray-600">Items per page:</span>
|
||||||
<div class="dropdown dropdown-top">
|
<div class="dropdown dropdown-top">
|
||||||
<div
|
<div
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ const isActive = (routeName: string) => {
|
||||||
? 'bg-dark text-white hover:bg-dark'
|
? 'bg-dark text-white hover:bg-dark'
|
||||||
: '',
|
: '',
|
||||||
]"
|
]"
|
||||||
data-tip="Rekam Medis"
|
data-tip="Medical Records"
|
||||||
@click="navigateTo('rekam-medis')"
|
@click="navigateTo('rekam-medis')"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
|
|
@ -167,7 +167,7 @@ const isActive = (routeName: string) => {
|
||||||
</svg>
|
</svg>
|
||||||
<span
|
<span
|
||||||
class="is-drawer-close:hidden is-drawer-open:opacity-100 transition-opacity is-drawer-open:duration-300 is-drawer-open:delay-300"
|
class="is-drawer-close:hidden is-drawer-open:opacity-100 transition-opacity is-drawer-open:duration-300 is-drawer-open:delay-300"
|
||||||
>Rekam<span class="opacity-0">_</span>Medis</span
|
>Medical<span class="opacity-0">_</span>Records</span
|
||||||
>
|
>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -181,7 +181,7 @@ const isActive = (routeName: string) => {
|
||||||
? 'bg-dark text-white hover:bg-dark'
|
? 'bg-dark text-white hover:bg-dark'
|
||||||
: '',
|
: '',
|
||||||
]"
|
]"
|
||||||
data-tip="Pemberian Tindakan"
|
data-tip="Doctor Actions"
|
||||||
@click="navigateTo('pemberian-tindakan')"
|
@click="navigateTo('pemberian-tindakan')"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
|
|
@ -204,7 +204,7 @@ const isActive = (routeName: string) => {
|
||||||
</svg>
|
</svg>
|
||||||
<span
|
<span
|
||||||
class="is-drawer-close:hidden is-drawer-open:opacity-100 transition-opacity is-drawer-open:duration-300 is-drawer-open:delay-300"
|
class="is-drawer-close:hidden is-drawer-open:opacity-100 transition-opacity is-drawer-open:duration-300 is-drawer-open:delay-300"
|
||||||
>Tindakan</span
|
>Actions</span
|
||||||
>
|
>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -216,7 +216,7 @@ const isActive = (routeName: string) => {
|
||||||
'mb-1 is-drawer-close:tooltip is-drawer-close:tooltip-right active:bg-dark',
|
'mb-1 is-drawer-close:tooltip is-drawer-close:tooltip-right active:bg-dark',
|
||||||
isActive('obat') ? 'bg-dark text-white hover:bg-dark' : '',
|
isActive('obat') ? 'bg-dark text-white hover:bg-dark' : '',
|
||||||
]"
|
]"
|
||||||
data-tip="Obat"
|
data-tip="Medicine Administration"
|
||||||
@click="navigateTo('obat')"
|
@click="navigateTo('obat')"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
|
|
@ -236,7 +236,7 @@ const isActive = (routeName: string) => {
|
||||||
</svg>
|
</svg>
|
||||||
<span
|
<span
|
||||||
class="is-drawer-close:hidden is-drawer-open:opacity-100 transition-opacity is-drawer-open:duration-300 is-drawer-open:delay-300"
|
class="is-drawer-close:hidden is-drawer-open:opacity-100 transition-opacity is-drawer-open:duration-300 is-drawer-open:delay-300"
|
||||||
>Obat</span
|
>Medicine</span
|
||||||
>
|
>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -248,7 +248,7 @@ const isActive = (routeName: string) => {
|
||||||
'mb-1 is-drawer-close:tooltip is-drawer-close:tooltip-right active:bg-dark',
|
'mb-1 is-drawer-close:tooltip is-drawer-close:tooltip-right active:bg-dark',
|
||||||
isActive('validasi') ? 'bg-dark text-white hover:bg-dark' : '',
|
isActive('validasi') ? 'bg-dark text-white hover:bg-dark' : '',
|
||||||
]"
|
]"
|
||||||
data-tip="Validasi"
|
data-tip="Validation"
|
||||||
@click="navigateTo('validasi')"
|
@click="navigateTo('validasi')"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
|
|
@ -268,7 +268,7 @@ const isActive = (routeName: string) => {
|
||||||
</svg>
|
</svg>
|
||||||
<span
|
<span
|
||||||
class="is-drawer-close:hidden is-drawer-open:opacity-100 transition-opacity is-drawer-open:duration-300 is-drawer-open:delay-300"
|
class="is-drawer-close:hidden is-drawer-open:opacity-100 transition-opacity is-drawer-open:duration-300 is-drawer-open:delay-300"
|
||||||
>Validasi</span
|
>Validation</span
|
||||||
>
|
>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -404,10 +404,10 @@ const isActive = (routeName: string) => {
|
||||||
<!-- Logout Confirmation Dialog -->
|
<!-- Logout Confirmation Dialog -->
|
||||||
<DialogConfirm
|
<DialogConfirm
|
||||||
ref="logoutDialog"
|
ref="logoutDialog"
|
||||||
title="Keluar"
|
title="Logout"
|
||||||
message="Apakah Anda yakin ingin keluar dari aplikasi?"
|
message="Are you sure you want to logout from the application?"
|
||||||
confirm-text="Ya, Keluar"
|
confirm-text="Yes, Logout"
|
||||||
cancel-text="Batal"
|
cancel-text="Cancel"
|
||||||
@confirm="handleLogoutConfirm"
|
@confirm="handleLogoutConfirm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ export const FILTER = {
|
||||||
B: "B",
|
B: "B",
|
||||||
AB: "AB",
|
AB: "AB",
|
||||||
O: "O",
|
O: "O",
|
||||||
"Tidak Tahu": "Tidak Tahu",
|
Unknown: "Unknown",
|
||||||
},
|
},
|
||||||
KATEGORI_TINDAKAN: {
|
KATEGORI_TINDAKAN: {
|
||||||
radiologi: "Radiologi",
|
radiologi: "Radiologi",
|
||||||
|
|
@ -63,34 +63,34 @@ export const FILTER = {
|
||||||
laboratorium: "LABORATORIUM",
|
laboratorium: "LABORATORIUM",
|
||||||
},
|
},
|
||||||
AUDIT_TYPE: {
|
AUDIT_TYPE: {
|
||||||
all: "Semua Tipe",
|
all: "All Types",
|
||||||
rekam_medis: "Rekam Medis",
|
rekam_medis: "Medical Records",
|
||||||
tindakan: "Tindakan",
|
tindakan: "Actions",
|
||||||
obat: "Obat",
|
obat: "Medicine",
|
||||||
proof: "Proof",
|
proof: "Proof",
|
||||||
},
|
},
|
||||||
AUDIT_TAMPERED: {
|
AUDIT_TAMPERED: {
|
||||||
all: "Semua Data",
|
all: "All Data",
|
||||||
tampered: "Termanipulasi",
|
tampered: "Tampered",
|
||||||
clean: "Tidak Termanipulasi",
|
clean: "Not Tampered",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SORT_OPTIONS = {
|
export const SORT_OPTIONS = {
|
||||||
REKAM_MEDIS: {
|
REKAM_MEDIS: {
|
||||||
waktu_visit: "ID Visit",
|
waktu_visit: "Visit ID",
|
||||||
no_rm: "Nomor Rekam Medis",
|
no_rm: "Medical Record Number",
|
||||||
umur: "Umur",
|
umur: "Age",
|
||||||
},
|
},
|
||||||
TINDAKAN: {
|
TINDAKAN: {
|
||||||
id: "ID",
|
id: "ID",
|
||||||
id_visit: "ID Visit",
|
id_visit: "Visit ID",
|
||||||
},
|
},
|
||||||
OBAT: {
|
OBAT: {
|
||||||
id: "ID",
|
id: "ID",
|
||||||
id_visit: "ID Visit",
|
id_visit: "Visit ID",
|
||||||
jumlah_obat: "Jumlah Obat",
|
jumlah_obat: "Medicine Amount",
|
||||||
obat: "Obat",
|
obat: "Medicine Name",
|
||||||
},
|
},
|
||||||
USERS: {
|
USERS: {
|
||||||
id: "ID",
|
id: "ID",
|
||||||
|
|
@ -98,9 +98,9 @@ export const SORT_OPTIONS = {
|
||||||
role: "Role",
|
role: "Role",
|
||||||
},
|
},
|
||||||
VALIDATION: {
|
VALIDATION: {
|
||||||
id: "ID Validasi",
|
id: "Validation ID",
|
||||||
created_at: "Waktu Dibuat",
|
created_at: "Created At",
|
||||||
processed_at: "Waktu Diproses",
|
processed_at: "Processed At",
|
||||||
},
|
},
|
||||||
AUDIT_TRAIL: {
|
AUDIT_TRAIL: {
|
||||||
last_sync: "Last Sync",
|
last_sync: "Last Sync",
|
||||||
|
|
@ -111,47 +111,47 @@ export const SORT_OPTIONS = {
|
||||||
export const REKAM_MEDIS_TABLE_COLUMNS = [
|
export const REKAM_MEDIS_TABLE_COLUMNS = [
|
||||||
{
|
{
|
||||||
key: "id_visit" as keyof RekamMedis,
|
key: "id_visit" as keyof RekamMedis,
|
||||||
label: "ID Visit",
|
label: "Visit ID",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "no_rm" as keyof RekamMedis,
|
key: "no_rm" as keyof RekamMedis,
|
||||||
label: "No RM",
|
label: "Medical Record Number",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "nama_pasien" as keyof RekamMedis,
|
key: "nama_pasien" as keyof RekamMedis,
|
||||||
label: "Nama Pasien",
|
label: "Patient Name",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "waktu_visit" as keyof RekamMedis,
|
key: "waktu_visit" as keyof RekamMedis,
|
||||||
label: "Waktu Visit",
|
label: "Visit Time",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "umur" as keyof RekamMedis,
|
key: "umur" as keyof RekamMedis,
|
||||||
label: "Umur",
|
label: "Age",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "jenis_kelamin" as keyof RekamMedis,
|
key: "jenis_kelamin" as keyof RekamMedis,
|
||||||
label: "Jenis Kelamin",
|
label: "Gender",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "gol_darah" as keyof RekamMedis,
|
key: "gol_darah" as keyof RekamMedis,
|
||||||
label: "Golongan Darah",
|
label: "Blood Type",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "kode_diagnosa" as keyof RekamMedis,
|
key: "kode_diagnosa" as keyof RekamMedis,
|
||||||
label: "Kode Diagnosa",
|
label: "Diagnosis Code",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "tindak_lanjut" as keyof RekamMedis,
|
key: "tindak_lanjut" as keyof RekamMedis,
|
||||||
label: "Tindak Lanjut",
|
label: "Follow-up Action",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@ -164,22 +164,22 @@ export const TINDAKAN_TABLE_COLUMNS = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "id_visit" as keyof TindakanDokter,
|
key: "id_visit" as keyof TindakanDokter,
|
||||||
label: "ID Visit",
|
label: "Visit ID",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "tindakan" as keyof TindakanDokter,
|
key: "tindakan" as keyof TindakanDokter,
|
||||||
label: "Tindakan",
|
label: "Action",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "kategori_tindakan" as keyof TindakanDokter,
|
key: "kategori_tindakan" as keyof TindakanDokter,
|
||||||
label: "Kategori Tindakan",
|
label: "Action Category",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "kelompok_tindakan" as keyof TindakanDokter,
|
key: "kelompok_tindakan" as keyof TindakanDokter,
|
||||||
label: "Kelompok Tindakan",
|
label: "Action Group",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@ -192,7 +192,7 @@ export const USERS_TABLE_COLUMNS = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "name" as keyof Users,
|
key: "name" as keyof Users,
|
||||||
label: "Nama Lengkap",
|
label: "Full Name",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -221,7 +221,7 @@ export const USERS_TABLE_COLUMNS = [
|
||||||
export const LOG_TABLE_COLUMNS = [
|
export const LOG_TABLE_COLUMNS = [
|
||||||
{
|
{
|
||||||
key: "txId" as keyof BlockchainLog,
|
key: "txId" as keyof BlockchainLog,
|
||||||
label: "ID Transaksi",
|
label: "Transaction ID",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -259,27 +259,27 @@ export const VALIDATION_TABLE_COLUMNS = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "table_name" as keyof ValidationLog,
|
key: "table_name" as keyof ValidationLog,
|
||||||
label: "Kelompok Data",
|
label: "Data Group",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "record_id" as keyof ValidationLog,
|
key: "record_id" as keyof ValidationLog,
|
||||||
label: "ID Record",
|
label: "Record ID",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "action" as keyof ValidationLog,
|
key: "action" as keyof ValidationLog,
|
||||||
label: "Aksi",
|
label: "Action",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "user_id_request" as keyof ValidationLog,
|
key: "user_id_request" as keyof ValidationLog,
|
||||||
label: "User ID Request",
|
label: "Requesting User ID",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "user_id_process" as keyof ValidationLog,
|
key: "user_id_process" as keyof ValidationLog,
|
||||||
label: "User ID Proses",
|
label: "Processing User ID",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -289,12 +289,12 @@ export const VALIDATION_TABLE_COLUMNS = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "created_at" as keyof ValidationLog,
|
key: "created_at" as keyof ValidationLog,
|
||||||
label: "Waktu Dibuat",
|
label: "Created At",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "processed_at" as keyof ValidationLog,
|
key: "processed_at" as keyof ValidationLog,
|
||||||
label: "Waktu Diproses",
|
label: "Processed At",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
const JENIS_KELAMIN_OPTIONS = ["laki-laki", "perempuan"] as const;
|
const JENIS_KELAMIN_OPTIONS = ["laki-laki", "perempuan"] as const;
|
||||||
const GOLONGAN_DARAH_OPTIONS = ["A", "B", "AB", "O", "Tidak Tahu"] as const;
|
const GOLONGAN_DARAH_OPTIONS = ["A", "B", "AB", "O", "Unknown"] as const;
|
||||||
const TINDAK_LANJUT_OPTIONS = [
|
const TINDAK_LANJUT_OPTIONS = [
|
||||||
"Dipulangkan untuk Kontrol",
|
"Dipulangkan untuk Kontrol",
|
||||||
"Dirawat",
|
"Dirawat",
|
||||||
|
|
@ -82,66 +82,69 @@ const numericString = (message: string, options?: NumericFieldOptions) =>
|
||||||
|
|
||||||
export const rekamMedisFormSchema = z
|
export const rekamMedisFormSchema = z
|
||||||
.object({
|
.object({
|
||||||
no_rm: trimmedString("No Rekam Medis wajib diisi", {
|
no_rm: trimmedString("Medical record number is required", {
|
||||||
max: {
|
max: {
|
||||||
value: 20,
|
value: 20,
|
||||||
message: "Nomor rekam medis maksimal 20 karakter",
|
message: "Medical record number must be at most 20 characters",
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
nama_pasien: trimmedString("Nama pasien wajib diisi", {
|
nama_pasien: trimmedString("Patient name is required", {
|
||||||
max: {
|
max: {
|
||||||
value: 100,
|
value: 100,
|
||||||
message: "Nama pasien maksimal 100 karakter",
|
message: "Patient name must be at most 100 characters",
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
umur: numericString("Umur wajib diisi dan harus valid", {
|
umur: numericString("Age is required and must be valid", {
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 150,
|
max: 150,
|
||||||
}),
|
}),
|
||||||
jenis_kelamin: z
|
jenis_kelamin: z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.refine((value) => isJenisKelaminOption(value), "Pilih jenis kelamin"),
|
.refine((value) => isJenisKelaminOption(value), "Please select gender"),
|
||||||
gol_darah: z
|
gol_darah: z
|
||||||
.array(z.string().trim())
|
.array(z.string().trim())
|
||||||
.min(1, "Pilih golongan darah")
|
.min(1, "Please select blood type")
|
||||||
.refine(
|
.refine(
|
||||||
(values) => values.every((value) => isGolonganDarahOption(value)),
|
(values) => values.every((value) => isGolonganDarahOption(value)),
|
||||||
"Golongan darah tidak valid"
|
"Invalid blood type"
|
||||||
),
|
),
|
||||||
pekerjaan: trimmedString("Pekerjaan wajib diisi"),
|
pekerjaan: trimmedString("Occupation is required"),
|
||||||
anamnese: trimmedString("Anamnese wajib diisi"),
|
anamnese: trimmedString("Anamnese is required"),
|
||||||
kode_diagnosa: trimmedString("Kode diagnosa wajib diisi"),
|
kode_diagnosa: trimmedString("Diagnosis code is required"),
|
||||||
diagnosa: trimmedString("Diagnosa wajib diisi"),
|
diagnosa: trimmedString("Diagnosis is required"),
|
||||||
diastolik: numericString("Tekanan diastolik harus diisi dan valid", {
|
diastolik: numericString(
|
||||||
|
"Diastolic pressure is required and must be valid",
|
||||||
|
{
|
||||||
|
min: 0,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
sistolik: numericString("Systolic pressure is required and must be valid", {
|
||||||
min: 0,
|
min: 0,
|
||||||
}),
|
}),
|
||||||
sistolik: numericString("Tekanan sistolik harus diisi dan valid", {
|
nadi: numericString("Pulse is required and must be valid", {
|
||||||
min: 0,
|
min: 0,
|
||||||
}),
|
}),
|
||||||
nadi: numericString("Nadi harus diisi dan valid", {
|
nafas: numericString("Respiration is required and must be valid", {
|
||||||
min: 0,
|
min: 0,
|
||||||
}),
|
}),
|
||||||
nafas: numericString("Nafas harus diisi dan valid", {
|
suhu: numericString("Temperature is required and must be valid", {
|
||||||
min: 0,
|
|
||||||
}),
|
|
||||||
suhu: numericString("Suhu harus diisi dan valid", {
|
|
||||||
min: 25,
|
min: 25,
|
||||||
max: 45,
|
max: 45,
|
||||||
}),
|
}),
|
||||||
tinggi_badan: numericString("Tinggi badan harus diisi dan valid", {
|
tinggi_badan: numericString("Height is required and must be valid", {
|
||||||
min: 0,
|
min: 0,
|
||||||
}),
|
}),
|
||||||
berat_badan: numericString("Berat badan harus diisi dan valid", {
|
berat_badan: numericString("Weight is required and must be valid", {
|
||||||
min: 0,
|
min: 0,
|
||||||
}),
|
}),
|
||||||
jenis_kasus: trimmedString("Jenis kasus wajib diisi"),
|
jenis_kasus: trimmedString("Case type is required"),
|
||||||
tindak_lanjut: z
|
tindak_lanjut: z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.refine(
|
.refine(
|
||||||
(value) => isTindakLanjutOption(value),
|
(value) => isTindakLanjutOption(value),
|
||||||
"Pastikan Tindak Lanjut Valid"
|
"Please select a valid follow-up option"
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
.passthrough();
|
.passthrough();
|
||||||
|
|
|
||||||
|
|
@ -54,29 +54,29 @@ const isKelompokTindakanOption = (value: string): value is KelompokTindakan =>
|
||||||
const kategoriTindakanSchema = z
|
const kategoriTindakanSchema = z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.min(1, "Kategori tindakan wajib diisi")
|
.min(1, "Action category is required")
|
||||||
.refine(isKategoriTindakanOption, "Pastikan kategori tindakan valid")
|
.refine(isKategoriTindakanOption, "Please select a valid action category")
|
||||||
.transform((value) => value as KategoriTindakan);
|
.transform((value) => value as KategoriTindakan);
|
||||||
|
|
||||||
const kelompokTindakanSchema = z
|
const kelompokTindakanSchema = z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.min(1, "Kelompok tindakan wajib diisi")
|
.min(1, "Action group is required")
|
||||||
.refine(isKelompokTindakanOption, "Pastikan kelompok tindakan valid")
|
.refine(isKelompokTindakanOption, "Please select a valid action group")
|
||||||
.transform((value) => value as KelompokTindakan);
|
.transform((value) => value as KelompokTindakan);
|
||||||
|
|
||||||
export const tindakanFormSchema = z
|
export const tindakanFormSchema = z
|
||||||
.object({
|
.object({
|
||||||
id_visit: trimmedString("ID Visit wajib diisi", {
|
id_visit: trimmedString("Visit ID is required", {
|
||||||
max: {
|
max: {
|
||||||
value: 50,
|
value: 50,
|
||||||
message: "ID Visit maksimal 50 karakter",
|
message: "Visit ID must be at most 50 characters",
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
tindakan: trimmedString("Nama tindakan wajib diisi", {
|
tindakan: trimmedString("Action name is required", {
|
||||||
max: {
|
max: {
|
||||||
value: 150,
|
value: 150,
|
||||||
message: "Nama tindakan maksimal 150 karakter",
|
message: "Action name must be at most 150 characters",
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
kategori_tindakan: kategoriTindakanSchema,
|
kategori_tindakan: kategoriTindakanSchema,
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@
|
||||||
class="h-screen w-screen flex justify-center flex-col items-center bg-white text-dark text-lg"
|
class="h-screen w-screen flex justify-center flex-col items-center bg-white text-dark text-lg"
|
||||||
>
|
>
|
||||||
<h1 class="font-bold">404 - Page Not Found</h1>
|
<h1 class="font-bold">404 - Page Not Found</h1>
|
||||||
<p>Halaman tidak ditemukan.</p>
|
<p>Page not found.</p>
|
||||||
<router-link to="/dashboard"
|
<router-link to="/dashboard"
|
||||||
>Kembali ke <span class="font-bold">Dashboard</span></router-link
|
>Back to <span class="font-bold">Dashboard</span></router-link
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,12 @@ import { useRouter } from "vue-router";
|
||||||
const validationSchema = toTypedSchema(
|
const validationSchema = toTypedSchema(
|
||||||
zod.object({
|
zod.object({
|
||||||
username: zod
|
username: zod
|
||||||
.string({ message: "Input tidak valid" })
|
.string({ message: "Invalid input" })
|
||||||
.min(1, { message: "Masukkan username" }),
|
.min(1, { message: "Please enter username" }),
|
||||||
password: zod
|
password: zod
|
||||||
.string({ message: "Input tidak valid" })
|
.string({ message: "Invalid input" })
|
||||||
.min(1, { message: "Masukkan password" })
|
.min(1, { message: "Please enter password" })
|
||||||
.min(6, { message: "Password minimal 6 karakter" }),
|
.min(6, { message: "Password must be at least 6 characters" }),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@ const onSubmit = handleSubmit(async (values: any) => {
|
||||||
if (error && Array.isArray(error.message)) {
|
if (error && Array.isArray(error.message)) {
|
||||||
loginError.value = error.message[0];
|
loginError.value = error.message[0];
|
||||||
} else {
|
} else {
|
||||||
loginError.value = error.message || "Terjadi kesalahan saat login.";
|
loginError.value = error.message || "An error occurred during login.";
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
|
|
@ -63,7 +63,7 @@ const onSubmit = handleSubmit(async (values: any) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const baseButtonClass =
|
const baseButtonClass =
|
||||||
"btn btn-primary hover:btn-primary-content text-white font-bold border-primary py-4 px-4 rounded-md focus:outline-none focus:shadow-outline w-full";
|
"btn bg-dark text-white font-bold py-4 px-4 rounded-md focus:outline-none focus:shadow-outline w-full";
|
||||||
|
|
||||||
const buttonClass = computed(() => {
|
const buttonClass = computed(() => {
|
||||||
return [
|
return [
|
||||||
|
|
@ -96,7 +96,7 @@ const buttonClass = computed(() => {
|
||||||
class="shadow appearance-none border rounded w-full py-2 px-3 mb-1 text-dark leading-tight focus:outline-none focus:shadow-outline"
|
class="shadow appearance-none border rounded w-full py-2 px-3 mb-1 text-dark leading-tight focus:outline-none focus:shadow-outline"
|
||||||
id="username"
|
id="username"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Masukkan username"
|
placeholder="Enter username"
|
||||||
/>
|
/>
|
||||||
<span class="text-red-800">{{ usernameError }}</span>
|
<span class="text-red-800">{{ usernameError }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -109,7 +109,7 @@ const buttonClass = computed(() => {
|
||||||
class="shadow appearance-none border rounded w-full py-2 px-3 text-dark mb-1 leading-tight focus:outline-none focus:shadow-outline"
|
class="shadow appearance-none border rounded w-full py-2 px-3 text-dark mb-1 leading-tight focus:outline-none focus:shadow-outline"
|
||||||
id="password"
|
id="password"
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="Masukkan password"
|
placeholder="Enter password"
|
||||||
/>
|
/>
|
||||||
<span class="text-red-800">{{ passwordError }}</span>
|
<span class="text-red-800">{{ passwordError }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -119,7 +119,7 @@ const buttonClass = computed(() => {
|
||||||
v-if="isLoading"
|
v-if="isLoading"
|
||||||
class="loading loading-dots loading-sm"
|
class="loading loading-dots loading-sm"
|
||||||
></span>
|
></span>
|
||||||
<span v-else>Masuk</span>
|
<span v-else>Sign In</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ const rekamMedisCountLineChartData = computed(() => {
|
||||||
labels: labels,
|
labels: labels,
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: "Jumlah Rekam Medis Baru",
|
label: "New Medical Records Count",
|
||||||
backgroundColor: "#1a2a4f",
|
backgroundColor: "#1a2a4f",
|
||||||
borderColor: "#1a2a4f",
|
borderColor: "#1a2a4f",
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
|
|
@ -123,7 +123,7 @@ const rekamMedisLineChartOptions = ref({
|
||||||
callbacks: {
|
callbacks: {
|
||||||
label: function (context: any) {
|
label: function (context: any) {
|
||||||
return (
|
return (
|
||||||
context.dataset.label + ": " + context.parsed.y + " rekam medis"
|
context.dataset.label + ": " + context.parsed.y + " medical records"
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -159,10 +159,10 @@ const rekamMedisLineChartOptions = ref({
|
||||||
});
|
});
|
||||||
|
|
||||||
const auditDataPerKelompokData = computed(() => ({
|
const auditDataPerKelompokData = computed(() => ({
|
||||||
labels: ["Rekam Medis", "Pemberian Tindakan", "Obat"],
|
labels: ["Medical Records", "Doctor Actions", "Medicine"],
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: "Jumlah Data",
|
label: "Data Count",
|
||||||
backgroundColor: "#1a2a4f",
|
backgroundColor: "#1a2a4f",
|
||||||
data: stats.tamperedDataPerKelompok.value,
|
data: stats.tamperedDataPerKelompok.value,
|
||||||
},
|
},
|
||||||
|
|
@ -200,11 +200,11 @@ const auditBarOption = {
|
||||||
const normalizeTableName = (tableName: string) => {
|
const normalizeTableName = (tableName: string) => {
|
||||||
switch (tableName) {
|
switch (tableName) {
|
||||||
case "rekam_medis":
|
case "rekam_medis":
|
||||||
return "Rekam Medis";
|
return "Medical Records";
|
||||||
case "pemberian_tindakan":
|
case "pemberian_tindakan":
|
||||||
return "Pemberian Tindakan";
|
return "Doctor Actions";
|
||||||
case "obat":
|
case "pemberian_obat":
|
||||||
return "Obat";
|
return "Medicine Administration";
|
||||||
default:
|
default:
|
||||||
return tableName;
|
return tableName;
|
||||||
}
|
}
|
||||||
|
|
@ -262,31 +262,33 @@ onMounted(() => {
|
||||||
<div class="bg-light w-full text-dark">
|
<div class="bg-light w-full text-dark">
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader title="Dashboard" subtitle="Detail Dashboard" />
|
<PageHeader title="Dashboard" subtitle="Dashboard Details" />
|
||||||
<div>
|
<div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 mt-4">
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 mt-4">
|
||||||
<div
|
<div
|
||||||
class="bg-white p-4 rounded-lg shadow-md flex flex-col items-center"
|
class="bg-white p-4 rounded-lg shadow-md flex flex-col items-center"
|
||||||
>
|
>
|
||||||
<h2 class="text-lg font-semibold mb-2">Total Rekam Medis</h2>
|
<h2 class="text-lg font-semibold mb-2">Total Medical Records</h2>
|
||||||
<p class="text-3xl font-bold">{{ stats.countRekamMedis }}</p>
|
<p class="text-3xl font-bold">{{ stats.countRekamMedis }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="bg-white p-4 rounded-lg shadow-md flex flex-col items-center"
|
class="bg-white p-4 rounded-lg shadow-md flex flex-col items-center"
|
||||||
>
|
>
|
||||||
<h2 class="text-lg font-semibold mb-2">Total Tindakan Dokter</h2>
|
<h2 class="text-lg font-semibold mb-2">Total Doctor Actions</h2>
|
||||||
<p class="text-3xl font-bold">{{ stats.countTindakanDokter }}</p>
|
<p class="text-3xl font-bold">{{ stats.countTindakanDokter }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="bg-white p-4 rounded-lg shadow-md flex flex-col items-center"
|
class="bg-white p-4 rounded-lg shadow-md flex flex-col items-center"
|
||||||
>
|
>
|
||||||
<h2 class="text-lg font-semibold mb-2">Total Obat</h2>
|
<h2 class="text-lg font-semibold mb-2">
|
||||||
|
Total Medicine Administration
|
||||||
|
</h2>
|
||||||
<p class="text-3xl font-bold">{{ stats.countObat }}</p>
|
<p class="text-3xl font-bold">{{ stats.countObat }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="bg-white p-4 rounded-lg shadow-md flex flex-col items-center"
|
class="bg-white p-4 rounded-lg shadow-md flex flex-col items-center"
|
||||||
>
|
>
|
||||||
<h2 class="text-lg font-semibold mb-2">Total Data Audit</h2>
|
<h2 class="text-lg font-semibold mb-2">Total Audit Data</h2>
|
||||||
<p class="text-3xl font-bold">
|
<p class="text-3xl font-bold">
|
||||||
{{ stats.auditNonTampered.value + stats.auditTampered.value }}
|
{{ stats.auditNonTampered.value + stats.auditTampered.value }}
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -297,7 +299,7 @@ onMounted(() => {
|
||||||
class="flex flex-col flex-2 mt-4 bg-white p-4 rounded-lg shadow-md min-w-0"
|
class="flex flex-col flex-2 mt-4 bg-white p-4 rounded-lg shadow-md min-w-0"
|
||||||
>
|
>
|
||||||
<h5 class="flex-1 text-lg font-semibold text-center">
|
<h5 class="flex-1 text-lg font-semibold text-center">
|
||||||
Jumlah Rekam Medis Baru 7 Hari Terakhir
|
New Medical Records in Last 7 Days
|
||||||
</h5>
|
</h5>
|
||||||
<div class="flex-5 w-full">
|
<div class="flex-5 w-full">
|
||||||
<Line
|
<Line
|
||||||
|
|
@ -310,13 +312,13 @@ onMounted(() => {
|
||||||
to="/rekam-medis"
|
to="/rekam-medis"
|
||||||
class="text-sm hover:opacity-75 transition-all"
|
class="text-sm hover:opacity-75 transition-all"
|
||||||
>
|
>
|
||||||
Lihat Data Rekam Medis >>
|
View Medical Records >>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1 mt-4 bg-white p-4 rounded-lg shadow-md min-w-0">
|
<div class="flex-1 mt-4 bg-white p-4 rounded-lg shadow-md min-w-0">
|
||||||
<h5 class="text-lg font-semibold mb-2 text-center">
|
<h5 class="text-lg font-semibold mb-2 text-center">
|
||||||
Data Audit Trail
|
Audit Trail Summary
|
||||||
</h5>
|
</h5>
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<Doughnut
|
<Doughnut
|
||||||
|
|
@ -339,7 +341,7 @@ onMounted(() => {
|
||||||
to="/audit-trail"
|
to="/audit-trail"
|
||||||
class="text-sm hover:opacity-75 transition-all"
|
class="text-sm hover:opacity-75 transition-all"
|
||||||
>
|
>
|
||||||
Lihat Detail Audit Trail >>
|
View Audit Trail Details >>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -347,17 +349,17 @@ onMounted(() => {
|
||||||
<div class="flex gap-x-4">
|
<div class="flex gap-x-4">
|
||||||
<div class="mt-4 flex-2 bg-white p-4 rounded-lg shadow-md h-fit">
|
<div class="mt-4 flex-2 bg-white p-4 rounded-lg shadow-md h-fit">
|
||||||
<h5 class="text-lg font-semibold text-center">
|
<h5 class="text-lg font-semibold text-center">
|
||||||
Data yang perlu divalidasi (<span
|
Data pending validation (<span class="font-bold text-red-400">{{
|
||||||
class="font-bold text-red-400"
|
validasiData.totalCount
|
||||||
>{{ validasiData.totalCount }}</span
|
}}</span
|
||||||
>)
|
>)
|
||||||
</h5>
|
</h5>
|
||||||
<table class="w-full mt-4">
|
<table class="w-full mt-4">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="text-left">
|
<tr class="text-left">
|
||||||
<th class="pb-2">Kelompok Data</th>
|
<th class="pb-2">Data Group</th>
|
||||||
<th class="pb-2">Tipe Aksi</th>
|
<th class="pb-2">Action Type</th>
|
||||||
<th class="pb-2">ID User</th>
|
<th class="pb-2">User ID</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="">
|
<tbody class="">
|
||||||
|
|
@ -383,13 +385,13 @@ onMounted(() => {
|
||||||
to="/validasi"
|
to="/validasi"
|
||||||
class="text-sm hover:opacity-75 transition-all"
|
class="text-sm hover:opacity-75 transition-all"
|
||||||
>
|
>
|
||||||
Lihat Detail Validasi Data >>
|
View Validation Details >>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-4 flex-1 bg-white p-4 rounded-lg shadow-md">
|
<div class="mt-4 flex-1 bg-white p-4 rounded-lg shadow-md">
|
||||||
<h5 class="text-lg font-semibold text-center">
|
<h5 class="text-lg font-semibold text-center">
|
||||||
Tampered data per kelompok data
|
Tampered data per data group
|
||||||
</h5>
|
</h5>
|
||||||
<div class="h-64 w-full">
|
<div class="h-64 w-full">
|
||||||
<Bar
|
<Bar
|
||||||
|
|
|
||||||
|
|
@ -139,11 +139,11 @@ const deriveType = (entry: Partial<AuditLogEntry>): AuditLogType => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const typeLabelMap: Record<AuditLogType, string> = {
|
const typeLabelMap: Record<AuditLogType, string> = {
|
||||||
rekam_medis: "Rekam Medis",
|
rekam_medis: "Medical Records",
|
||||||
tindakan: "Tindakan",
|
tindakan: "Actions",
|
||||||
obat: "Obat",
|
obat: "Medicine",
|
||||||
proof: "Proof",
|
proof: "Proof",
|
||||||
unknown: "Tidak Diketahui",
|
unknown: "Unknown",
|
||||||
};
|
};
|
||||||
|
|
||||||
const normalizeEntry = (entry: any): AuditLogEntry => {
|
const normalizeEntry = (entry: any): AuditLogEntry => {
|
||||||
|
|
@ -343,17 +343,17 @@ onMounted(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("connect", () => {
|
socket.on("connect", () => {
|
||||||
console.log("Berhasil terhubung ke WebSocket:", socket.id);
|
console.log("Successfully connected to WebSocket:", socket.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("audit.progress", (data) => {
|
socket.on("audit.progress", (data) => {
|
||||||
console.log("Menerima progres:", data);
|
console.log("Receiving progress:", data);
|
||||||
status.value = "RUNNING";
|
status.value = "RUNNING";
|
||||||
progres.value = data.progress_count;
|
progres.value = data.progress_count;
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("audit.complete", (data) => {
|
socket.on("audit.complete", (data) => {
|
||||||
console.log("Menerima selesai:", data);
|
console.log("Receiving completion:", data);
|
||||||
fetchData();
|
fetchData();
|
||||||
status.value = "COMPLETED";
|
status.value = "COMPLETED";
|
||||||
});
|
});
|
||||||
|
|
@ -379,7 +379,7 @@ onBeforeUnmount(() => {
|
||||||
<div class="bg-light w-full text-dark">
|
<div class="bg-light w-full text-dark">
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader title="Audit Trail" subtitle="Riwayat Log Blockchain" />
|
<PageHeader title="Audit Trail" subtitle="Blockchain Log History" />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="collapse collapse-arrow bg-white border-white border shadow-sm mb-2"
|
class="collapse collapse-arrow bg-white border-white border shadow-sm mb-2"
|
||||||
|
|
@ -394,37 +394,37 @@ onBeforeUnmount(() => {
|
||||||
<div class="flex gap-x-4">
|
<div class="flex gap-x-4">
|
||||||
<div class="flex gap-x-4 items-end">
|
<div class="flex gap-x-4 items-end">
|
||||||
<div class="h-full">
|
<div class="h-full">
|
||||||
<label for="jenis_kelamin" class="font-bold">Tipe Data</label>
|
<label for="jenis_kelamin" class="font-bold">Data Type</label>
|
||||||
<select
|
<select
|
||||||
v-model="filters.type"
|
v-model="filters.type"
|
||||||
class="select bg-white border border-gray-300 mt-1"
|
class="select bg-white border border-gray-300 mt-1"
|
||||||
>
|
>
|
||||||
<option disabled selected value="initial">
|
<option disabled selected value="initial">
|
||||||
Pilih Tipe Data
|
Select Data Type
|
||||||
</option>
|
</option>
|
||||||
<option value="rekam_medis">Rekam Medis</option>
|
<option value="rekam_medis">Medical Records</option>
|
||||||
<option value="tindakan">Tindakan</option>
|
<option value="tindakan">Doctors Actions</option>
|
||||||
<option value="obat">Obat</option>
|
<option value="obat">Medicine Administration</option>
|
||||||
<option value="proof">Proof</option>
|
<option value="proof">Proof</option>
|
||||||
<option value="all">Semua Tipe</option>
|
<option value="all">All Types</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-x-4 items-end">
|
<div class="flex gap-x-4 items-end">
|
||||||
<div class="h-full">
|
<div class="h-full">
|
||||||
<label for="jenis_kelamin" class="font-bold"
|
<label for="jenis_kelamin" class="font-bold"
|
||||||
>Status Manipulasi</label
|
>Tampering Status</label
|
||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
v-model="filters.tampered"
|
v-model="filters.tampered"
|
||||||
class="select bg-white border border-gray-300 mt-1"
|
class="select bg-white border border-gray-300 mt-1"
|
||||||
>
|
>
|
||||||
<option disabled selected value="initial">
|
<option disabled selected value="initial">
|
||||||
Pilih Status Manipulasi
|
Select Tampering Status
|
||||||
</option>
|
</option>
|
||||||
<option value="tampered">Tampered</option>
|
<option value="tampered">Tampered</option>
|
||||||
<option value="non_tampered">Non-tampered</option>
|
<option value="non_tampered">Non-tampered</option>
|
||||||
<option value="all">Semua</option>
|
<option value="all">All</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -448,14 +448,14 @@ onBeforeUnmount(() => {
|
||||||
<div class="flex flex-col w-full gap-2 md:flex-row md:items-center">
|
<div class="flex flex-col w-full gap-2 md:flex-row md:items-center">
|
||||||
<SearchInput
|
<SearchInput
|
||||||
v-model="searchId"
|
v-model="searchId"
|
||||||
placeholder="Cari berdasarkan ID Log"
|
placeholder="Search by Log ID (e.g., REKAM_12345)"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
/>
|
/>
|
||||||
<div class="flex items-center gap-2 md:ml-4">
|
<div class="flex items-center gap-2 md:ml-4">
|
||||||
<SortDropdown
|
<SortDropdown
|
||||||
v-model="sortBy"
|
v-model="sortBy"
|
||||||
:options="SORT_OPTIONS.AUDIT_TRAIL"
|
:options="SORT_OPTIONS.AUDIT_TRAIL"
|
||||||
label="Urut berdasarkan:"
|
label="Sort by:"
|
||||||
@change="handleSortChange"
|
@change="handleSortChange"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
|
|
@ -481,11 +481,11 @@ onBeforeUnmount(() => {
|
||||||
</div>
|
</div>
|
||||||
<DialogConfirm
|
<DialogConfirm
|
||||||
ref="auditDialog"
|
ref="auditDialog"
|
||||||
title="Konfirmasi"
|
title="Confirmation"
|
||||||
message="Apakah anda yakin ingin menjalankan audit? (Proses ini mungkin
|
message="Are you sure you want to run the audit? (This process may
|
||||||
memakan waktu lama)"
|
take a long time)"
|
||||||
confirm-text="Iya, Jalankan"
|
confirm-text="Yes, Run"
|
||||||
cancel-text="Batal"
|
cancel-text="Cancel"
|
||||||
@confirm="runAuditTrail"
|
@confirm="runAuditTrail"
|
||||||
/>
|
/>
|
||||||
<ButtonDark
|
<ButtonDark
|
||||||
|
|
@ -494,7 +494,7 @@ onBeforeUnmount(() => {
|
||||||
status === 'STARTING' ||
|
status === 'STARTING' ||
|
||||||
status === 'RUNNING'
|
status === 'RUNNING'
|
||||||
"
|
"
|
||||||
text="Lakukan Audit"
|
text="Run Audit"
|
||||||
@click="showAuditModal"
|
@click="showAuditModal"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -509,11 +509,9 @@ onBeforeUnmount(() => {
|
||||||
<div class="h-48 flex justify-center items-center flex-col gap-4">
|
<div class="h-48 flex justify-center items-center flex-col gap-4">
|
||||||
<span class="loading loading-ring loading-xl"></span>
|
<span class="loading loading-ring loading-xl"></span>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<p class="font-semibold mb-2">
|
<p class="font-semibold mb-2">Audit process is running...</p>
|
||||||
Proses audit sedang berjalan...
|
|
||||||
</p>
|
|
||||||
<p class="text-sm text-gray-600">
|
<p class="text-sm text-gray-600">
|
||||||
{{ progres }} data telah diperiksa
|
{{ progres }} data has been checked
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -523,7 +521,7 @@ onBeforeUnmount(() => {
|
||||||
:data="logs"
|
:data="logs"
|
||||||
:columns="AUDIT_TABLE_COLUMNS"
|
:columns="AUDIT_TABLE_COLUMNS"
|
||||||
:is-loading="api.isLoading.value"
|
:is-loading="api.isLoading.value"
|
||||||
empty-message="Tidak ada log audit"
|
empty-message="No audit logs available"
|
||||||
:is-aksi="false"
|
:is-aksi="false"
|
||||||
/>
|
/>
|
||||||
<PaginationControls
|
<PaginationControls
|
||||||
|
|
|
||||||
|
|
@ -103,23 +103,23 @@ const validate = (): CreateObatFormErrors => {
|
||||||
const validationErrors: CreateObatFormErrors = {};
|
const validationErrors: CreateObatFormErrors = {};
|
||||||
|
|
||||||
if (!data.value.id_visit.trim()) {
|
if (!data.value.id_visit.trim()) {
|
||||||
validationErrors.id_visit = "ID Visit wajib diisi";
|
validationErrors.id_visit = "ID Visit is required";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.value.obat.trim()) {
|
if (!data.value.obat.trim()) {
|
||||||
validationErrors.obat = "Nama obat wajib diisi";
|
validationErrors.obat = "Medicine name is required";
|
||||||
}
|
}
|
||||||
|
|
||||||
const jumlahRaw = data.value.jumlah_obat.trim();
|
const jumlahRaw = data.value.jumlah_obat.trim();
|
||||||
|
|
||||||
if (!jumlahRaw) {
|
if (!jumlahRaw) {
|
||||||
validationErrors.jumlah_obat = "Jumlah obat wajib diisi";
|
validationErrors.jumlah_obat = "Medicine quantity is required";
|
||||||
} else {
|
} else {
|
||||||
const jumlahNumber = Number(jumlahRaw);
|
const jumlahNumber = Number(jumlahRaw);
|
||||||
|
|
||||||
if (!Number.isInteger(jumlahNumber) || jumlahNumber <= 0) {
|
if (!Number.isInteger(jumlahNumber) || jumlahNumber <= 0) {
|
||||||
validationErrors.jumlah_obat =
|
validationErrors.jumlah_obat =
|
||||||
"Jumlah obat harus berupa bilangan bulat positif";
|
"Medicine quantity must be a positive integer";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,7 +164,7 @@ const handleSubmit = async () => {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to create obat:", error);
|
console.error("Failed to create obat:", error);
|
||||||
submitError.value =
|
submitError.value =
|
||||||
(error as ApiError)?.message || "Gagal menyimpan data obat.";
|
(error as ApiError)?.message || "Failed to save medicine data.";
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +194,7 @@ watch(
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.title = "Tambah Pemberian Obat - Hospital Log";
|
document.title = "Add Medicine Administration - Hospital Log";
|
||||||
fetchVisitOptions("");
|
fetchVisitOptions("");
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -203,19 +203,22 @@ onMounted(() => {
|
||||||
<div class="bg-light w-full text-dark">
|
<div class="bg-light w-full text-dark">
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader title="Pemberian Obat" subtitle="Tambah Pemberian Obat" />
|
<PageHeader
|
||||||
|
title="Medicine Administration"
|
||||||
|
subtitle="Add Medicine Administration"
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-md text-dark">
|
<div class="bg-white rounded-xl shadow-md text-dark">
|
||||||
<div class="flex flex-col px-4 py-4 justify-between gap-4">
|
<div class="flex flex-col px-4 py-4 justify-between gap-4">
|
||||||
<div class="breadcrumbs text-sm">
|
<div class="breadcrumbs text-sm">
|
||||||
<ul>
|
<ul>
|
||||||
<li class="font-bold">
|
<li class="font-bold">
|
||||||
<RouterLink to="/obat">Pemberian Obat</RouterLink>
|
<RouterLink to="/obat">Medicine Administration</RouterLink>
|
||||||
</li>
|
</li>
|
||||||
<li>Tambah Pemberian Obat</li>
|
<li>Add Medicine Administration</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<h5 class="font-bold">Tambah Pemberian Obat</h5>
|
<h5 class="font-bold">Add Medicine Administration</h5>
|
||||||
|
|
||||||
<div v-if="isSuccess" role="alert" class="alert alert-success">
|
<div v-if="isSuccess" role="alert" class="alert alert-success">
|
||||||
<svg
|
<svg
|
||||||
|
|
@ -231,7 +234,7 @@ onMounted(() => {
|
||||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span>Berhasil menambahkan data obat!</span>
|
<span>Successfully added medicine data!</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="submitError" role="alert" class="alert alert-error">
|
<div v-if="submitError" role="alert" class="alert alert-error">
|
||||||
|
|
@ -256,7 +259,7 @@ onMounted(() => {
|
||||||
v-if="isLoading"
|
v-if="isLoading"
|
||||||
>
|
>
|
||||||
<span class="loading loading-ring loading-xl"></span>
|
<span class="loading loading-ring loading-xl"></span>
|
||||||
<h5>Mohon tunggu, sedang menyimpan data obat...</h5>
|
<h5>Please wait, saving medicine data...</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form v-else @submit.prevent="handleSubmit" class="text-sm">
|
<form v-else @submit.prevent="handleSubmit" class="text-sm">
|
||||||
|
|
@ -264,7 +267,7 @@ onMounted(() => {
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
label="ID Visit"
|
label="ID Visit"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Masukkan ID visit"
|
placeholder="Enter visit ID"
|
||||||
v-model="data.id_visit"
|
v-model="data.id_visit"
|
||||||
:error="errors.id_visit || null"
|
:error="errors.id_visit || null"
|
||||||
list="visit-options"
|
list="visit-options"
|
||||||
|
|
@ -280,25 +283,25 @@ onMounted(() => {
|
||||||
</datalist>
|
</datalist>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-4"
|
class="mt-4"
|
||||||
label="Obat"
|
label="Medicine"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Masukkan nama obat"
|
placeholder="Enter medicine name"
|
||||||
v-model="data.obat"
|
v-model="data.obat"
|
||||||
:error="errors.obat || null"
|
:error="errors.obat || null"
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-4"
|
class="mt-4"
|
||||||
label="Jumlah Obat"
|
label="Medicine Quantity"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Masukkan jumlah obat"
|
placeholder="Enter medicine quantity"
|
||||||
v-model="data.jumlah_obat"
|
v-model="data.jumlah_obat"
|
||||||
:error="errors.jumlah_obat || null"
|
:error="errors.jumlah_obat || null"
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-4"
|
class="mt-4"
|
||||||
label="Aturan Pakai"
|
label="Usage Instructions"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Masukkan aturan pakai"
|
placeholder="Enter usage instructions"
|
||||||
v-model="data.aturan_pakai"
|
v-model="data.aturan_pakai"
|
||||||
:error="errors.aturan_pakai || null"
|
:error="errors.aturan_pakai || null"
|
||||||
/>
|
/>
|
||||||
|
|
@ -308,7 +311,7 @@ onMounted(() => {
|
||||||
>
|
>
|
||||||
<ButtonDark
|
<ButtonDark
|
||||||
type="submit"
|
type="submit"
|
||||||
:text="isLoading ? 'Menyimpan...' : 'Simpan Obat'"
|
:text="isLoading ? 'Saving...' : 'Save Medicine'"
|
||||||
:isLoading="isLoading"
|
:isLoading="isLoading"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ const fetchLogData = async () => {
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await fetchData();
|
await fetchData();
|
||||||
await fetchLogData();
|
await fetchLogData();
|
||||||
document.title = "Rekam Medis Detail - Hospital Log";
|
document.title = "Medicine Administration Detail - Hospital Log";
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -136,8 +136,8 @@ onMounted(async () => {
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="Pemberian Obat"
|
title="Medicine Administration"
|
||||||
:subtitle="`Detail Pemberian Obat. ID ${route.params.id}`"
|
:subtitle="`Medicine Administration Detail. ID ${route.params.id}`"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-md text-dark">
|
<div class="bg-white rounded-xl shadow-md text-dark">
|
||||||
|
|
@ -145,21 +145,21 @@ onMounted(async () => {
|
||||||
<div class="breadcrumbs text-sm">
|
<div class="breadcrumbs text-sm">
|
||||||
<ul>
|
<ul>
|
||||||
<li class="font-bold">
|
<li class="font-bold">
|
||||||
<RouterLink to="/obat">Pemberian Obat</RouterLink>
|
<RouterLink to="/obat">Medicine Administration</RouterLink>
|
||||||
</li>
|
</li>
|
||||||
<li>Detail Pemberian Obat {{ route.params.id }}</li>
|
<li>Medicine Administration Detail {{ route.params.id }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<h5 class="font-bold">Detail Pemberian Obat</h5>
|
<h5 class="font-bold">Medicine Administration Detail</h5>
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p>ID: {{ data?.id }}</p>
|
<p>ID: {{ data?.id }}</p>
|
||||||
<p>ID Visit: {{ data?.id_visit }}</p>
|
<p>ID Visit: {{ data?.id_visit }}</p>
|
||||||
<p>Obat: {{ data?.obat }}</p>
|
<p>Medicine: {{ data?.obat }}</p>
|
||||||
<p>Jumlah Obat: {{ data?.jumlah_obat }}</p>
|
<p>Medicine Quantity: {{ data?.jumlah_obat }}</p>
|
||||||
<p>Aturan Pakai: {{ data?.aturan_pakai }}</p>
|
<p>Usage Instructions: {{ data?.aturan_pakai }}</p>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<h5 class="font-bold">Log Perubahan</h5>
|
<h5 class="font-bold">Change Log</h5>
|
||||||
<div role="alert" class="alert alert-error" v-if="isTampered">
|
<div role="alert" class="alert alert-error" v-if="isTampered">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|
@ -174,13 +174,13 @@ onMounted(async () => {
|
||||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span>Peringatan! Manipulasi Data Terdeteksi.</span>
|
<span>Warning! Data Manipulation Detected.</span>
|
||||||
</div>
|
</div>
|
||||||
<DataTable
|
<DataTable
|
||||||
:data="dataLog"
|
:data="dataLog"
|
||||||
:columns="LOG_TABLE_COLUMNS"
|
:columns="LOG_TABLE_COLUMNS"
|
||||||
:is-loading="api.isLoading.value"
|
:is-loading="api.isLoading.value"
|
||||||
empty-message="Belum terdapat log perubahan"
|
empty-message="No change logs available yet"
|
||||||
:is-aksi="false"
|
:is-aksi="false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -51,15 +51,15 @@ const sortOrder = ref<"asc" | "desc">(
|
||||||
const tableColumns = [
|
const tableColumns = [
|
||||||
{ key: "id" as keyof ObatData, label: "#", class: "text-dark" },
|
{ key: "id" as keyof ObatData, label: "#", class: "text-dark" },
|
||||||
{ key: "id_visit" as keyof ObatData, label: "ID Visit", class: "text-dark" },
|
{ key: "id_visit" as keyof ObatData, label: "ID Visit", class: "text-dark" },
|
||||||
{ key: "obat" as keyof ObatData, label: "Obat", class: "text-dark" },
|
{ key: "obat" as keyof ObatData, label: "Medicine", class: "text-dark" },
|
||||||
{
|
{
|
||||||
key: "jumlah_obat" as keyof ObatData,
|
key: "jumlah_obat" as keyof ObatData,
|
||||||
label: "Jumlah Obat",
|
label: "Medicine Quantity",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "aturan_pakai" as keyof ObatData,
|
key: "aturan_pakai" as keyof ObatData,
|
||||||
label: "Aturan Pakai",
|
label: "Usage Instructions",
|
||||||
class: "text-dark",
|
class: "text-dark",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@ -207,7 +207,10 @@ onMounted(async () => {
|
||||||
<div class="bg-light w-full text-dark">
|
<div class="bg-light w-full text-dark">
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader title="Obat" subtitle="Manajemen Obat" />
|
<PageHeader
|
||||||
|
title="Medicine Administration"
|
||||||
|
subtitle="Medicine Management"
|
||||||
|
/>
|
||||||
<div class="bg-white rounded-xl shadow-md">
|
<div class="bg-white rounded-xl shadow-md">
|
||||||
<div
|
<div
|
||||||
class="flex flex-col md:flex-row md:items-center md:justify-between gap-4 px-4 pt-4 pb-2"
|
class="flex flex-col md:flex-row md:items-center md:justify-between gap-4 px-4 pt-4 pb-2"
|
||||||
|
|
@ -215,14 +218,14 @@ onMounted(async () => {
|
||||||
<div class="flex flex-col w-full gap-2 md:flex-row md:items-center">
|
<div class="flex flex-col w-full gap-2 md:flex-row md:items-center">
|
||||||
<SearchInput
|
<SearchInput
|
||||||
v-model="searchObat"
|
v-model="searchObat"
|
||||||
placeholder="Cari berdasarkan Obat"
|
placeholder="Search by Medicine Administration ID"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
/>
|
/>
|
||||||
<div class="flex items-center gap-2 md:ml-4">
|
<div class="flex items-center gap-2 md:ml-4">
|
||||||
<SortDropdown
|
<SortDropdown
|
||||||
v-model="sortBy"
|
v-model="sortBy"
|
||||||
:options="SORT_OPTIONS.OBAT"
|
:options="SORT_OPTIONS.OBAT"
|
||||||
label="Urut berdasarkan:"
|
label="Sort by:"
|
||||||
@change="handleSortChange"
|
@change="handleSortChange"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
|
|
@ -250,7 +253,7 @@ onMounted(async () => {
|
||||||
to="/pemberian-obat-add"
|
to="/pemberian-obat-add"
|
||||||
class="btn bg-dark btn-sm self-start md:self-auto"
|
class="btn bg-dark btn-sm self-start md:self-auto"
|
||||||
>
|
>
|
||||||
Tambah Obat
|
Add Medicine
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -272,7 +275,7 @@ onMounted(async () => {
|
||||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span>Data obat berhasil dikirim untuk validasi penghapusan</span>
|
<span>Medicine data successfully sent for deletion validation</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Data Table -->
|
<!-- Data Table -->
|
||||||
|
|
@ -280,7 +283,7 @@ onMounted(async () => {
|
||||||
:data="data"
|
:data="data"
|
||||||
:columns="tableColumns"
|
:columns="tableColumns"
|
||||||
:is-loading="api.isLoading.value"
|
:is-loading="api.isLoading.value"
|
||||||
empty-message="Tidak ada data obat"
|
empty-message="No medicine data available"
|
||||||
@details="handleDetails"
|
@details="handleDetails"
|
||||||
@update="handleUpdate"
|
@update="handleUpdate"
|
||||||
@delete="handleDelete"
|
@delete="handleDelete"
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ const handleSubmit = async () => {
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
if (id.value === data.value.id) {
|
if (id.value === data.value.id) {
|
||||||
if (id.value !== parseInt(route.params.id as string)) {
|
if (id.value !== parseInt(route.params.id as string)) {
|
||||||
alert("ID tidak valid. Data akan dimuat ulang.");
|
alert("Invalid ID. Data will be reloaded.");
|
||||||
await fetchData();
|
await fetchData();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -181,7 +181,7 @@ const fetchLogData = async () => {
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await fetchData();
|
await fetchData();
|
||||||
await fetchLogData();
|
await fetchLogData();
|
||||||
document.title = "Rekam Medis Detail - Hospital Log";
|
document.title = "Medicine Administration Detail - Hospital Log";
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -190,8 +190,8 @@ onMounted(async () => {
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="Pemberian Obat"
|
title="Medicine Administration"
|
||||||
:subtitle="`Update Pemberian Obat. ID ${route.params.id}`"
|
:subtitle="`Update Medicine Administration. ID ${route.params.id}`"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-md text-dark">
|
<div class="bg-white rounded-xl shadow-md text-dark">
|
||||||
|
|
@ -199,12 +199,12 @@ onMounted(async () => {
|
||||||
<div class="breadcrumbs text-sm">
|
<div class="breadcrumbs text-sm">
|
||||||
<ul>
|
<ul>
|
||||||
<li class="font-bold">
|
<li class="font-bold">
|
||||||
<RouterLink to="/obat">Pemberian Obat</RouterLink>
|
<RouterLink to="/obat">Medicine Administration</RouterLink>
|
||||||
</li>
|
</li>
|
||||||
<li>Update Pemberian Obat {{ route.params.id }}</li>
|
<li>Update Medicine Administration {{ route.params.id }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<h5 class="font-bold">Update Pemberian Obat</h5>
|
<h5 class="font-bold">Update Medicine Administration</h5>
|
||||||
<div v-if="isSuccess" role="alert" class="alert alert-success">
|
<div v-if="isSuccess" role="alert" class="alert alert-success">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|
@ -219,7 +219,7 @@ onMounted(async () => {
|
||||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span>Berhasil memperbarui data!</span>
|
<span>Successfully updated data!</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<form @submit.prevent="handleSubmit">
|
<form @submit.prevent="handleSubmit">
|
||||||
|
|
@ -239,40 +239,40 @@ onMounted(async () => {
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
label="Obat"
|
label="Medicine"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.obat"
|
v-model="data.obat"
|
||||||
:is-disabled="false"
|
:is-disabled="false"
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
label="Jumlah Obat"
|
label="Medicine Quantity"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.jumlah_obat"
|
v-model="data.jumlah_obat"
|
||||||
:is-disabled="false"
|
:is-disabled="false"
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
label="Aturan Pakai"
|
label="Usage Instructions"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Belum ada aturan pakai."
|
placeholder="No usage instructions yet."
|
||||||
v-model="data.aturan_pakai"
|
v-model="data.aturan_pakai"
|
||||||
:is-disabled="false"
|
:is-disabled="false"
|
||||||
/>
|
/>
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<ButtonDark
|
<ButtonDark
|
||||||
type="submit"
|
type="submit"
|
||||||
:text="isLoading ? 'Menyimpan...' : 'Simpan Perubahan'"
|
:text="isLoading ? 'Saving...' : 'Save Changes'"
|
||||||
class="mt-4"
|
class="mt-4"
|
||||||
:isLoading="isLoading"
|
:isLoading="isLoading"
|
||||||
>
|
>
|
||||||
Simpan Perubahan
|
Save Changes
|
||||||
</ButtonDark>
|
</ButtonDark>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<h5 class="font-bold">Log Perubahan</h5>
|
<h5 class="font-bold">Change Log</h5>
|
||||||
<div role="alert" class="alert alert-error" v-if="isTampered">
|
<div role="alert" class="alert alert-error" v-if="isTampered">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|
@ -287,13 +287,13 @@ onMounted(async () => {
|
||||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span>Peringatan! Manipulasi Data Terdeteksi.</span>
|
<span>Warning! Data tampering detected.</span>
|
||||||
</div>
|
</div>
|
||||||
<DataTable
|
<DataTable
|
||||||
:data="dataLog"
|
:data="dataLog"
|
||||||
:columns="LOG_TABLE_COLUMNS"
|
:columns="LOG_TABLE_COLUMNS"
|
||||||
:is-loading="api.isLoading.value"
|
:is-loading="api.isLoading.value"
|
||||||
empty-message="Belum terdapat log perubahan"
|
empty-message="No change logs yet"
|
||||||
:is-aksi="false"
|
:is-aksi="false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ const handleSubmit = async () => {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to create tindakan:", error);
|
console.error("Failed to create tindakan:", error);
|
||||||
submitError.value =
|
submitError.value =
|
||||||
(error as ApiError)?.message || "Gagal menyimpan data tindakan.";
|
(error as ApiError)?.message || "Failed to save action data.";
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|
@ -158,7 +158,7 @@ watch(
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.title = "Tambah Pemberian Tindakan - Hospital Log";
|
document.title = "Add Doctor Action - Hospital Log";
|
||||||
fetchVisitOptions("");
|
fetchVisitOptions("");
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -167,10 +167,7 @@ onMounted(() => {
|
||||||
<div class="bg-light w-full text-dark">
|
<div class="bg-light w-full text-dark">
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader
|
<PageHeader title="Doctor Action" subtitle="Add Doctor Action" />
|
||||||
title="Pemberian Tindakan"
|
|
||||||
subtitle="Tambah Pemberian Tindakan"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-md text-dark">
|
<div class="bg-white rounded-xl shadow-md text-dark">
|
||||||
<div class="flex flex-col px-4 py-4 justify-between gap-4">
|
<div class="flex flex-col px-4 py-4 justify-between gap-4">
|
||||||
|
|
@ -178,13 +175,13 @@ onMounted(() => {
|
||||||
<ul>
|
<ul>
|
||||||
<li class="font-bold">
|
<li class="font-bold">
|
||||||
<RouterLink to="/pemberian-tindakan"
|
<RouterLink to="/pemberian-tindakan"
|
||||||
>Pemberian Tindakan</RouterLink
|
>Doctor Action</RouterLink
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
<li>Tambah Pemberian Tindakan</li>
|
<li>Add Doctor Action</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<h5 class="font-bold">Tambah Pemberian Tindakan</h5>
|
<h5 class="font-bold">Add Doctor Action</h5>
|
||||||
|
|
||||||
<div v-if="isSuccess" role="alert" class="alert alert-success">
|
<div v-if="isSuccess" role="alert" class="alert alert-success">
|
||||||
<svg
|
<svg
|
||||||
|
|
@ -200,7 +197,7 @@ onMounted(() => {
|
||||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span>Berhasil menambahkan data tindakan!</span>
|
<span>Successfully added action data!</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="submitError" role="alert" class="alert alert-error">
|
<div v-if="submitError" role="alert" class="alert alert-error">
|
||||||
|
|
@ -225,15 +222,15 @@ onMounted(() => {
|
||||||
v-if="isLoading"
|
v-if="isLoading"
|
||||||
>
|
>
|
||||||
<span class="loading loading-ring loading-xl"></span>
|
<span class="loading loading-ring loading-xl"></span>
|
||||||
<h5>Mohon tunggu, sedang menyimpan data tindakan...</h5>
|
<h5>Please wait, saving action data...</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form v-else @submit.prevent="handleSubmit" class="text-sm">
|
<form v-else @submit.prevent="handleSubmit" class="text-sm">
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
label="ID Visit"
|
label="Visit ID"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Masukkan ID visit"
|
placeholder="Enter visit ID"
|
||||||
v-model="data.id_visit"
|
v-model="data.id_visit"
|
||||||
:error="errors.id_visit || null"
|
:error="errors.id_visit || null"
|
||||||
list="visit-options"
|
list="visit-options"
|
||||||
|
|
@ -249,16 +246,16 @@ onMounted(() => {
|
||||||
</datalist>
|
</datalist>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-4"
|
class="mt-4"
|
||||||
label="Tindakan"
|
label="Doctor Action"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Masukkan nama tindakan"
|
placeholder="Enter action name"
|
||||||
v-model="data.tindakan"
|
v-model="data.tindakan"
|
||||||
:error="errors.tindakan || null"
|
:error="errors.tindakan || null"
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Kategori Tindakan"
|
placeholder="Enter doctor action category"
|
||||||
label="Kategori Tindakan"
|
label="Doctor Action Category"
|
||||||
list="kategori_tindakan"
|
list="kategori_tindakan"
|
||||||
v-model="data.kategori_tindakan"
|
v-model="data.kategori_tindakan"
|
||||||
:error="errors.kategori_tindakan || null"
|
:error="errors.kategori_tindakan || null"
|
||||||
|
|
@ -274,8 +271,8 @@ onMounted(() => {
|
||||||
</datalist>
|
</datalist>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Kelompok Tindakan"
|
placeholder="Enter doctor action group"
|
||||||
label="Kelompok Tindakan"
|
label="Doctor Action Group"
|
||||||
list="kelompok_tindakan"
|
list="kelompok_tindakan"
|
||||||
v-model="data.kelompok_tindakan"
|
v-model="data.kelompok_tindakan"
|
||||||
:error="errors.kelompok_tindakan || null"
|
:error="errors.kelompok_tindakan || null"
|
||||||
|
|
@ -294,7 +291,7 @@ onMounted(() => {
|
||||||
>
|
>
|
||||||
<ButtonDark
|
<ButtonDark
|
||||||
type="submit"
|
type="submit"
|
||||||
:text="isLoading ? 'Menyimpan...' : 'Simpan Tindakan'"
|
:text="isLoading ? 'Saving...' : 'Save Action'"
|
||||||
:isLoading="isLoading"
|
:isLoading="isLoading"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ const fetchLogData = async () => {
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await fetchData();
|
await fetchData();
|
||||||
await fetchLogData();
|
await fetchLogData();
|
||||||
document.title = `Detail Pemberian Tindakan - ID ${route.params.id}`;
|
document.title = `Doctor Action Details - ID ${route.params.id}`;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -137,8 +137,8 @@ onMounted(async () => {
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="Pemberian Tindakan"
|
title="Doctor Actions"
|
||||||
:subtitle="`Detail Pemberian Tindakan ${route.params.id}`"
|
:subtitle="`Doctor Action Details ${route.params.id}`"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-md text-dark">
|
<div class="bg-white rounded-xl shadow-md text-dark">
|
||||||
|
|
@ -147,28 +147,28 @@ onMounted(async () => {
|
||||||
<ul>
|
<ul>
|
||||||
<li class="font-bold">
|
<li class="font-bold">
|
||||||
<RouterLink to="/pemberian-tindakan">
|
<RouterLink to="/pemberian-tindakan">
|
||||||
Pemberian Tindakan
|
Doctor Actions
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</li>
|
</li>
|
||||||
<li>Detail Pemberian Tindakan {{ route.params.id }}</li>
|
<li>Doctor Action Details {{ route.params.id }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<h5 class="font-bold">Detail Pemberian Tindakan</h5>
|
<h5 class="font-bold">Doctor Action Details</h5>
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p>ID: {{ tindakan?.id }}</p>
|
<p>ID: {{ tindakan?.id }}</p>
|
||||||
<p>ID Visit: {{ tindakan?.id_visit }}</p>
|
<p>Visit ID: {{ tindakan?.id_visit }}</p>
|
||||||
<p>Tindakan: {{ tindakan?.tindakan }}</p>
|
<p>Doctor Action: {{ tindakan?.tindakan }}</p>
|
||||||
<p>
|
<p>
|
||||||
Kategori Tindakan:
|
Doctor Action Category:
|
||||||
{{ tindakan?.kategori_tindakan || "-" }}
|
{{ tindakan?.kategori_tindakan || "-" }}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Kelompok Tindakan:
|
Doctor Action Group:
|
||||||
{{ tindakan?.kelompok_tindakan || "-" }}
|
{{ tindakan?.kelompok_tindakan || "-" }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<h5 class="font-bold">Log Perubahan</h5>
|
<h5 class="font-bold">Change Log</h5>
|
||||||
<div role="alert" class="alert alert-error" v-if="isTampered">
|
<div role="alert" class="alert alert-error" v-if="isTampered">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|
@ -183,14 +183,14 @@ onMounted(async () => {
|
||||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span>Peringatan! Manipulasi Data Terdeteksi.</span>
|
<span>Warning! Data Manipulation Detected.</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DataTable
|
<DataTable
|
||||||
:data="dataLog"
|
:data="dataLog"
|
||||||
:columns="LOG_TABLE_COLUMNS"
|
:columns="LOG_TABLE_COLUMNS"
|
||||||
:is-loading="api.isLoading.value"
|
:is-loading="api.isLoading.value"
|
||||||
empty-message="Belum terdapat log perubahan"
|
empty-message="No change logs available yet"
|
||||||
:is-aksi="false"
|
:is-aksi="false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -275,7 +275,7 @@ const handleSubmit = async () => {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to update tindakan:", error);
|
console.error("Failed to update tindakan:", error);
|
||||||
submitError.value =
|
submitError.value =
|
||||||
(error as ApiError)?.message || "Gagal memperbarui data tindakan.";
|
(error as ApiError)?.message || "Failed to update action data.";
|
||||||
} finally {
|
} finally {
|
||||||
isSubmitting.value = false;
|
isSubmitting.value = false;
|
||||||
}
|
}
|
||||||
|
|
@ -312,7 +312,7 @@ onMounted(async () => {
|
||||||
fetchLogData(),
|
fetchLogData(),
|
||||||
fetchVisitOptions(""),
|
fetchVisitOptions(""),
|
||||||
]);
|
]);
|
||||||
document.title = `Edit Pemberian Tindakan - ID ${routeId.value}`;
|
document.title = `Edit Doctor Action - ID ${routeId.value}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
|
@ -342,8 +342,8 @@ watch(
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="Pemberian Tindakan"
|
title="Doctor Actions"
|
||||||
:subtitle="`Update Pemberian Tindakan ${routeId}`"
|
:subtitle="`Update Doctor Action ${routeId}`"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-md text-dark">
|
<div class="bg-white rounded-xl shadow-md text-dark">
|
||||||
|
|
@ -352,13 +352,13 @@ watch(
|
||||||
<ul>
|
<ul>
|
||||||
<li class="font-bold">
|
<li class="font-bold">
|
||||||
<RouterLink to="/pemberian-tindakan">
|
<RouterLink to="/pemberian-tindakan">
|
||||||
Pemberian Tindakan
|
Doctor Actions
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</li>
|
</li>
|
||||||
<li>Update Pemberian Tindakan {{ routeId }}</li>
|
<li>Update Doctor Action {{ routeId }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<h5 class="font-bold">Update Pemberian Tindakan</h5>
|
<h5 class="font-bold">Update Doctor Action</h5>
|
||||||
|
|
||||||
<div v-if="isSuccess" role="alert" class="alert alert-success">
|
<div v-if="isSuccess" role="alert" class="alert alert-success">
|
||||||
<svg
|
<svg
|
||||||
|
|
@ -374,7 +374,7 @@ watch(
|
||||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span>Berhasil memperbarui data!</span>
|
<span>Successfully updated data!</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="submitError" role="alert" class="alert alert-error">
|
<div v-if="submitError" role="alert" class="alert alert-error">
|
||||||
|
|
@ -399,7 +399,7 @@ watch(
|
||||||
v-if="isInitialLoading"
|
v-if="isInitialLoading"
|
||||||
>
|
>
|
||||||
<span class="loading loading-ring loading-xl"></span>
|
<span class="loading loading-ring loading-xl"></span>
|
||||||
<h5>Memuat data tindakan...</h5>
|
<h5>Loading action data...</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form v-else @submit.prevent="handleSubmit" class="text-sm">
|
<form v-else @submit.prevent="handleSubmit" class="text-sm">
|
||||||
|
|
@ -412,9 +412,9 @@ watch(
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-4"
|
class="mt-4"
|
||||||
label="ID Visit"
|
label="Visit ID"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Masukkan ID visit"
|
placeholder="Enter visit ID"
|
||||||
v-model="data.id_visit"
|
v-model="data.id_visit"
|
||||||
:error="errors.id_visit || null"
|
:error="errors.id_visit || null"
|
||||||
list="visit-options"
|
list="visit-options"
|
||||||
|
|
@ -430,16 +430,16 @@ watch(
|
||||||
</datalist>
|
</datalist>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-4"
|
class="mt-4"
|
||||||
label="Tindakan"
|
label="Doctor Action"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Masukkan nama tindakan"
|
placeholder="Enter doctor action name"
|
||||||
v-model="data.tindakan"
|
v-model="data.tindakan"
|
||||||
:error="errors.tindakan || null"
|
:error="errors.tindakan || null"
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Kategori Tindakan"
|
placeholder="Enter doctor action category"
|
||||||
label="Kategori Tindakan"
|
label="Doctor Action Category"
|
||||||
list="kategori_tindakan"
|
list="kategori_tindakan"
|
||||||
v-model="data.kategori_tindakan"
|
v-model="data.kategori_tindakan"
|
||||||
:error="errors.kategori_tindakan || null"
|
:error="errors.kategori_tindakan || null"
|
||||||
|
|
@ -455,8 +455,8 @@ watch(
|
||||||
</datalist>
|
</datalist>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Kelompok Tindakan"
|
placeholder="Enter doctor action group"
|
||||||
label="Kelompok Tindakan"
|
label="Doctor Action Group"
|
||||||
list="kelompok_tindakan"
|
list="kelompok_tindakan"
|
||||||
v-model="data.kelompok_tindakan"
|
v-model="data.kelompok_tindakan"
|
||||||
:error="errors.kelompok_tindakan || null"
|
:error="errors.kelompok_tindakan || null"
|
||||||
|
|
@ -475,14 +475,14 @@ watch(
|
||||||
>
|
>
|
||||||
<ButtonDark
|
<ButtonDark
|
||||||
type="submit"
|
type="submit"
|
||||||
:text="isSubmitting ? 'Menyimpan...' : 'Simpan Perubahan'"
|
:text="isSubmitting ? 'Saving...' : 'Save Changes'"
|
||||||
:isLoading="isSubmitting"
|
:isLoading="isSubmitting"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
<h5 class="font-bold">Log Perubahan</h5>
|
<h5 class="font-bold">Change Log</h5>
|
||||||
<div role="alert" class="alert alert-error" v-if="isTampered">
|
<div role="alert" class="alert alert-error" v-if="isTampered">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|
@ -497,14 +497,14 @@ watch(
|
||||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span>Peringatan! Manipulasi Data Terdeteksi.</span>
|
<span>Warning! Data Manipulation Detected.</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DataTable
|
<DataTable
|
||||||
:data="dataLog"
|
:data="dataLog"
|
||||||
:columns="LOG_TABLE_COLUMNS"
|
:columns="LOG_TABLE_COLUMNS"
|
||||||
:is-loading="api.isLoading.value"
|
:is-loading="api.isLoading.value"
|
||||||
empty-message="Belum terdapat log perubahan"
|
empty-message="No change logs available yet"
|
||||||
:is-aksi="false"
|
:is-aksi="false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -72,25 +72,12 @@ const updateQueryParams = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
console.log("Fetch Data Params :", {
|
|
||||||
take: pagination.pageSize.value.toString(),
|
|
||||||
page: pagination.page.value.toString(),
|
|
||||||
orderBy: sortBy.value,
|
|
||||||
order: sortOrder.value,
|
|
||||||
...(searchIdVisit.value && { id_visit: searchIdVisit.value }),
|
|
||||||
...(filter.value.tindakan && { tindakan: filter.value.tindakan }),
|
|
||||||
...(filter.value.kategori.length > 0
|
|
||||||
? { kategori: filter.value.kategori.join(",") }
|
|
||||||
: {}),
|
|
||||||
...(filter.value.kelompok.length > 0
|
|
||||||
? { kelompok: filter.value.kelompok.join(",") }
|
|
||||||
: {}),
|
|
||||||
});
|
|
||||||
try {
|
try {
|
||||||
const queryParams = new URLSearchParams({
|
const queryParams = new URLSearchParams({
|
||||||
take: pagination.pageSize.value.toString(),
|
take: pagination.pageSize.value.toString(),
|
||||||
page: pagination.page.value.toString(),
|
page: pagination.page.value.toString(),
|
||||||
orderBy: sortBy.value,
|
orderBy: sortBy.value,
|
||||||
|
order: sortOrder.value,
|
||||||
...(searchIdVisit.value && { id_visit: searchIdVisit.value }),
|
...(searchIdVisit.value && { id_visit: searchIdVisit.value }),
|
||||||
...(filter.value.tindakan && { tindakan: filter.value.tindakan }),
|
...(filter.value.tindakan && { tindakan: filter.value.tindakan }),
|
||||||
...(filter.value.kategori.length > 0
|
...(filter.value.kategori.length > 0
|
||||||
|
|
@ -166,7 +153,10 @@ const handleSortChange = (newSortBy: string) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleSortOrder = () => {
|
const toggleSortOrder = () => {
|
||||||
|
console.log(sortOrder.value);
|
||||||
sortOrder.value = sortOrder.value === "asc" ? "desc" : "asc";
|
sortOrder.value = sortOrder.value === "asc" ? "desc" : "asc";
|
||||||
|
pagination.reset();
|
||||||
|
fetchData();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePageSizeChange = (newSize: number) => {
|
const handlePageSizeChange = (newSize: number) => {
|
||||||
|
|
@ -191,7 +181,7 @@ const handleDelete = async (item: TindakanDokter) => {
|
||||||
await fetchData();
|
await fetchData();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error deleting tindakan:", error);
|
console.error("Error deleting tindakan:", error);
|
||||||
alert("Gagal menghapus data tindakan");
|
alert("Failed to delete action data");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -226,7 +216,7 @@ onMounted(async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
await fetchData();
|
await fetchData();
|
||||||
document.title = "Tindakan Dokter - Hospital Log";
|
document.title = "Doctors Actions - Hospital Log";
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -235,8 +225,8 @@ onMounted(async () => {
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="Pemberian Tindakan"
|
title="Doctors Actions"
|
||||||
subtitle="Manajemen Pemberian Tindakan"
|
subtitle="Doctors Actions Management"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="collapse collapse-arrow bg-white border-white border shadow-sm mb-2"
|
class="collapse collapse-arrow bg-white border-white border shadow-sm mb-2"
|
||||||
|
|
@ -250,19 +240,19 @@ onMounted(async () => {
|
||||||
<div class="collapse-content text-sm flex flex-col">
|
<div class="collapse-content text-sm flex flex-col">
|
||||||
<div class="flex justify-between gap-4">
|
<div class="flex justify-between gap-4">
|
||||||
<div class="flex flex-col flex-1">
|
<div class="flex flex-col flex-1">
|
||||||
<label for="tindakan" class="font-bold">Tindakan</label>
|
<label for="tindakan" class="font-bold">Action</label>
|
||||||
<input
|
<input
|
||||||
class="mt-1 border border-gray-200 bg-gray-50 px-3 py-2 rounded-md shadow-sm focus:border-gray-300 focus:bg-gray-100 focus:outline-0 inset-shadow-gray-300 focus:inset-shadow-xs/80"
|
class="mt-1 border border-gray-200 bg-gray-50 px-3 py-2 rounded-md shadow-sm focus:border-gray-300 focus:bg-gray-100 focus:outline-0 inset-shadow-gray-300 focus:inset-shadow-xs/80"
|
||||||
type="text"
|
type="text"
|
||||||
name="tindakan"
|
name="tindakan"
|
||||||
id="tindakan"
|
id="tindakan"
|
||||||
placeholder="Masukkan Tindakan"
|
placeholder="Enter Action"
|
||||||
v-model="filter.tindakan"
|
v-model="filter.tindakan"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="h-full flex-1">
|
<div class="h-full flex-1">
|
||||||
<label for="kelompok_tindakan" class="font-bold"
|
<label for="kelompok_tindakan" class="font-bold"
|
||||||
>Kelompok tindakan</label
|
>Action Group</label
|
||||||
>
|
>
|
||||||
<form class="mt-2 flex flex-wrap gap-1 items-center">
|
<form class="mt-2 flex flex-wrap gap-1 items-center">
|
||||||
<input
|
<input
|
||||||
|
|
@ -287,7 +277,7 @@ onMounted(async () => {
|
||||||
</div>
|
</div>
|
||||||
<div class="h-full mt-4">
|
<div class="h-full mt-4">
|
||||||
<label for="kategori_tindakan" class="font-bold"
|
<label for="kategori_tindakan" class="font-bold"
|
||||||
>Kategori Tindakan</label
|
>Action Category</label
|
||||||
>
|
>
|
||||||
<form class="mt-1 flex flex-wrap gap-1">
|
<form class="mt-1 flex flex-wrap gap-1">
|
||||||
<input
|
<input
|
||||||
|
|
@ -322,7 +312,7 @@ onMounted(async () => {
|
||||||
@click="handleApplyFilter"
|
@click="handleApplyFilter"
|
||||||
class="btn btn-sm bg-dark hover:bg-light hover:text-dark active:inset-shadow-sm active:inset-shadow-black/50"
|
class="btn btn-sm bg-dark hover:bg-light hover:text-dark active:inset-shadow-sm active:inset-shadow-black/50"
|
||||||
>
|
>
|
||||||
Terapkan
|
Apply
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -334,14 +324,14 @@ onMounted(async () => {
|
||||||
<div class="flex flex-col w-full gap-2 md:flex-row md:items-center">
|
<div class="flex flex-col w-full gap-2 md:flex-row md:items-center">
|
||||||
<SearchInput
|
<SearchInput
|
||||||
v-model="searchIdVisit"
|
v-model="searchIdVisit"
|
||||||
placeholder="Cari berdasarkan ID Visit"
|
placeholder="Search by Visit ID"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
/>
|
/>
|
||||||
<div class="flex items-center gap-2 md:ml-4">
|
<div class="flex items-center gap-2 md:ml-4">
|
||||||
<SortDropdown
|
<SortDropdown
|
||||||
v-model="sortBy"
|
v-model="sortBy"
|
||||||
:options="SORT_OPTIONS.TINDAKAN"
|
:options="SORT_OPTIONS.TINDAKAN"
|
||||||
label="Urut berdasarkan:"
|
label="Sort by:"
|
||||||
@change="handleSortChange"
|
@change="handleSortChange"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
|
|
@ -369,7 +359,7 @@ onMounted(async () => {
|
||||||
to="/pemberian-tindakan/add"
|
to="/pemberian-tindakan/add"
|
||||||
class="btn btn-sm bg-dark text-light hover:bg-light hover:text-dark active:inset-shadow-sm active:inset-shadow-black/50 self-start md:self-auto"
|
class="btn btn-sm bg-dark text-light hover:bg-light hover:text-dark active:inset-shadow-sm active:inset-shadow-black/50 self-start md:self-auto"
|
||||||
>
|
>
|
||||||
Tambah Pemberian Tindakan
|
Add Doctors Action
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -391,9 +381,7 @@ onMounted(async () => {
|
||||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span
|
<span>Action data successfully sent for deletion validation</span>
|
||||||
>Data tindakan berhasil dikirim untuk validasi penghapusan</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Data Table -->
|
<!-- Data Table -->
|
||||||
|
|
@ -401,7 +389,7 @@ onMounted(async () => {
|
||||||
:data="data"
|
:data="data"
|
||||||
:columns="TINDAKAN_TABLE_COLUMNS"
|
:columns="TINDAKAN_TABLE_COLUMNS"
|
||||||
:is-loading="api.isLoading.value"
|
:is-loading="api.isLoading.value"
|
||||||
empty-message="Tidak ada data tindakan"
|
empty-message="No action data available"
|
||||||
@details="handleDetails"
|
@details="handleDetails"
|
||||||
@update="handleUpdate"
|
@update="handleUpdate"
|
||||||
@delete="handleDelete"
|
@delete="handleDelete"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import Sidebar from "../../../components/dashboard/Sidebar.vue";
|
||||||
import Footer from "../../../components/dashboard/Footer.vue";
|
import Footer from "../../../components/dashboard/Footer.vue";
|
||||||
import PageHeader from "../../../components/dashboard/PageHeader.vue";
|
import PageHeader from "../../../components/dashboard/PageHeader.vue";
|
||||||
import { onMounted, ref, watch } from "vue";
|
import { onMounted, ref, watch } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
|
||||||
import FieldInput from "../../../components/dashboard/FieldInput.vue";
|
import FieldInput from "../../../components/dashboard/FieldInput.vue";
|
||||||
import { FILTER } from "../../../constants/pagination";
|
import { FILTER } from "../../../constants/pagination";
|
||||||
import {
|
import {
|
||||||
|
|
@ -12,7 +11,6 @@ import {
|
||||||
} from "../../../validation/rekamMedis";
|
} from "../../../validation/rekamMedis";
|
||||||
import { useApi } from "../../../composables/useApi";
|
import { useApi } from "../../../composables/useApi";
|
||||||
|
|
||||||
const route = useRoute();
|
|
||||||
const api = useApi();
|
const api = useApi();
|
||||||
|
|
||||||
const data = ref<{
|
const data = ref<{
|
||||||
|
|
@ -233,7 +231,7 @@ watch(
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.title = "Tambah Rekam Medis - Hospital Log";
|
document.title = "Add Medical Record - Hospital Log";
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -242,8 +240,8 @@ onMounted(() => {
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="Rekam Medis"
|
title="Medical Record"
|
||||||
:subtitle="`Detail Rekam Medis ${route.params.id}`"
|
:subtitle="`Create New Medical Record`"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-md text-dark">
|
<div class="bg-white rounded-xl shadow-md text-dark">
|
||||||
|
|
@ -251,12 +249,12 @@ onMounted(() => {
|
||||||
<div class="breadcrumbs text-sm">
|
<div class="breadcrumbs text-sm">
|
||||||
<ul>
|
<ul>
|
||||||
<li class="font-bold">
|
<li class="font-bold">
|
||||||
<RouterLink to="/rekam-medis">Rekam Medis</RouterLink>
|
<RouterLink to="/rekam-medis">Medical Record</RouterLink>
|
||||||
</li>
|
</li>
|
||||||
<li>Tambah Rekam Medis</li>
|
<li>Add Medical Record</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<h5 class="font-bold">Tambah Rekam Medis</h5>
|
<h5 class="font-bold">Add Medical Record</h5>
|
||||||
<div v-if="isSuccess" role="alert" class="alert alert-success">
|
<div v-if="isSuccess" role="alert" class="alert alert-success">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|
@ -271,14 +269,14 @@ onMounted(() => {
|
||||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span>Berhasil menambahkan rekam medis!</span>
|
<span>Successfully added medical record!</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="flex h-screen flex-col justify-center gap-y-2 items-center"
|
class="flex h-screen flex-col justify-center gap-y-2 items-center"
|
||||||
v-if="isLoading"
|
v-if="isLoading"
|
||||||
>
|
>
|
||||||
<span class="loading loading-ring loading-xl"></span>
|
<span class="loading loading-ring loading-xl"></span>
|
||||||
<h5>Mohon tunggu, sedang menambahkan rekam medis...</h5>
|
<h5>Please wait, adding medical record...</h5>
|
||||||
</div>
|
</div>
|
||||||
<form
|
<form
|
||||||
@submit.prevent="handleSubmit"
|
@submit.prevent="handleSubmit"
|
||||||
|
|
@ -294,28 +292,28 @@ onMounted(() => {
|
||||||
<div
|
<div
|
||||||
class="collapse-title font-semibold text-base text-dark"
|
class="collapse-title font-semibold text-base text-dark"
|
||||||
>
|
>
|
||||||
Identitas Pasien
|
Patient Identity
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse-content">
|
<div class="collapse-content">
|
||||||
<FieldInput
|
<FieldInput
|
||||||
placeholder="Masukkan No. Rekam Medis"
|
placeholder="Enter Medical Record Number"
|
||||||
label="No Rekam Medis"
|
label="Medical Record Number"
|
||||||
v-model="data.no_rm"
|
v-model="data.no_rm"
|
||||||
:error="errors.no_rm"
|
:error="errors.no_rm"
|
||||||
:readonly="false"
|
:readonly="false"
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Nama Pasien"
|
placeholder="Enter Patient Name"
|
||||||
label="Nama Pasien"
|
label="Patient Name"
|
||||||
v-model="data.nama_pasien"
|
v-model="data.nama_pasien"
|
||||||
:error="errors.nama_pasien"
|
:error="errors.nama_pasien"
|
||||||
:readonly="false"
|
:readonly="false"
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Umur"
|
placeholder="Enter Age"
|
||||||
label="Umur"
|
label="Age"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.umur"
|
v-model="data.umur"
|
||||||
:error="errors.umur"
|
:error="errors.umur"
|
||||||
|
|
@ -323,7 +321,7 @@ onMounted(() => {
|
||||||
/>
|
/>
|
||||||
<div class="flex flex-col mt-2">
|
<div class="flex flex-col mt-2">
|
||||||
<label for="jenis_kelamin" class="font-bold"
|
<label for="jenis_kelamin" class="font-bold"
|
||||||
>Jenis Kelamin</label
|
>Gender</label
|
||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
v-model="data.jenis_kelamin"
|
v-model="data.jenis_kelamin"
|
||||||
|
|
@ -336,10 +334,10 @@ onMounted(() => {
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<option disabled selected value="initial">
|
<option disabled selected value="initial">
|
||||||
Pilih Jenis Kelamin
|
Select Gender
|
||||||
</option>
|
</option>
|
||||||
<option value="laki-laki">Laki-laki</option>
|
<option value="laki-laki">Male</option>
|
||||||
<option value="perempuan">Perempuan</option>
|
<option value="perempuan">Female</option>
|
||||||
</select>
|
</select>
|
||||||
<p
|
<p
|
||||||
v-if="errors.jenis_kelamin"
|
v-if="errors.jenis_kelamin"
|
||||||
|
|
@ -350,7 +348,7 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col mt-2">
|
<div class="flex flex-col mt-2">
|
||||||
<label for="golongan_darah" class="font-bold"
|
<label for="golongan_darah" class="font-bold"
|
||||||
>Golongan Darah</label
|
>Blood Type</label
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="filter mt-1 flex flex-wrap justify-start items-center"
|
class="filter mt-1 flex flex-wrap justify-start items-center"
|
||||||
|
|
@ -382,16 +380,16 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Pekerjaan"
|
placeholder="Enter Occupation (e.g., Teacher, Engineer, Student)"
|
||||||
label="Pekerjaan"
|
label="Occupation"
|
||||||
v-model="data.pekerjaan"
|
v-model="data.pekerjaan"
|
||||||
:error="errors.pekerjaan"
|
:error="errors.pekerjaan"
|
||||||
:readonly="false"
|
:readonly="false"
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Suku"
|
placeholder="Enter Ethnicity"
|
||||||
label="Suku"
|
label="Ethnicity"
|
||||||
v-model="data.suku"
|
v-model="data.suku"
|
||||||
:error="errors.suku"
|
:error="errors.suku"
|
||||||
:readonly="false"
|
:readonly="false"
|
||||||
|
|
@ -409,21 +407,21 @@ onMounted(() => {
|
||||||
<div
|
<div
|
||||||
class="collapse-title font-semibold text-base text-dark"
|
class="collapse-title font-semibold text-base text-dark"
|
||||||
>
|
>
|
||||||
Tanda-Tanda Vital
|
Vital Signs
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse-content">
|
<div class="collapse-content">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4">
|
||||||
<FieldInput
|
<FieldInput
|
||||||
placeholder="Masukkan Nadi (bpm)"
|
placeholder="Enter Pulse (bpm)"
|
||||||
label="Nadi (bpm)"
|
label="Pulse (bpm)"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.nadi"
|
v-model="data.nadi"
|
||||||
:error="errors.nadi"
|
:error="errors.nadi"
|
||||||
:readonly="false"
|
:readonly="false"
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
placeholder="Masukkan Nafas (per menit)"
|
placeholder="Enter Respiration (per minute)"
|
||||||
label="Nafas (per menit)"
|
label="Respiration (per minute)"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.nafas"
|
v-model="data.nafas"
|
||||||
:error="errors.nafas"
|
:error="errors.nafas"
|
||||||
|
|
@ -431,8 +429,8 @@ onMounted(() => {
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Sistolik (mmHg)"
|
placeholder="Enter Systolic Blood Pressure (mmHg)"
|
||||||
label="Tekanan Darah Sistolik (mmHg)"
|
label="Systolic Blood Pressure (mmHg)"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.sistolik"
|
v-model="data.sistolik"
|
||||||
:error="errors.sistolik"
|
:error="errors.sistolik"
|
||||||
|
|
@ -440,8 +438,8 @@ onMounted(() => {
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Diastolik (mmHg)"
|
placeholder="Enter Diastolic Blood Pressure (mmHg)"
|
||||||
label="Tekanan Darah Diastolik (mmHg)"
|
label="Diastolic Blood Pressure (mmHg)"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.diastolik"
|
v-model="data.diastolik"
|
||||||
:error="errors.diastolik"
|
:error="errors.diastolik"
|
||||||
|
|
@ -449,8 +447,8 @@ onMounted(() => {
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Suhu (°C)"
|
placeholder="Enter Body Temperature (°C)"
|
||||||
label="Suhu Tubuh (°C)"
|
label="Body Temperature (°C)"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.suhu"
|
v-model="data.suhu"
|
||||||
:error="errors.suhu"
|
:error="errors.suhu"
|
||||||
|
|
@ -458,8 +456,8 @@ onMounted(() => {
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Tinggi Badan (cm)"
|
placeholder="Enter Height (cm)"
|
||||||
label="Tinggi Badan (cm)"
|
label="Height (cm)"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.tinggi_badan"
|
v-model="data.tinggi_badan"
|
||||||
:error="errors.tinggi_badan"
|
:error="errors.tinggi_badan"
|
||||||
|
|
@ -467,8 +465,8 @@ onMounted(() => {
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Berat Badan (kg)"
|
placeholder="Enter Weight (kg)"
|
||||||
label="Berat Badan (kg)"
|
label="Weight (kg)"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.berat_badan"
|
v-model="data.berat_badan"
|
||||||
:error="errors.berat_badan"
|
:error="errors.berat_badan"
|
||||||
|
|
@ -486,7 +484,7 @@ onMounted(() => {
|
||||||
>
|
>
|
||||||
<input type="checkbox" checked />
|
<input type="checkbox" checked />
|
||||||
<div class="collapse-title font-semibold text-base text-dark">
|
<div class="collapse-title font-semibold text-base text-dark">
|
||||||
Informasi Medis
|
Medical Information
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse-content">
|
<div class="collapse-content">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
|
|
@ -494,7 +492,7 @@ onMounted(() => {
|
||||||
<textarea
|
<textarea
|
||||||
id="anamnese"
|
id="anamnese"
|
||||||
v-model="data.anamnese"
|
v-model="data.anamnese"
|
||||||
placeholder="Masukkan Anamnese"
|
placeholder="Enter Anamnese"
|
||||||
:class="[
|
:class="[
|
||||||
'textarea bg-white mt-1 min-h-[100px] border',
|
'textarea bg-white mt-1 min-h-[100px] border',
|
||||||
errors.anamnese
|
errors.anamnese
|
||||||
|
|
@ -509,18 +507,18 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Kode Diagnosa"
|
placeholder="Enter Diagnosis Code"
|
||||||
label="Kode Diagnosa"
|
label="Diagnosis Code"
|
||||||
v-model="data.kode_diagnosa"
|
v-model="data.kode_diagnosa"
|
||||||
:error="errors.kode_diagnosa"
|
:error="errors.kode_diagnosa"
|
||||||
:readonly="false"
|
:readonly="false"
|
||||||
/>
|
/>
|
||||||
<div class="flex flex-col mt-2">
|
<div class="flex flex-col mt-2">
|
||||||
<label for="diagnosa" class="font-bold">Diagnosa</label>
|
<label for="diagnosa" class="font-bold">Diagnosis</label>
|
||||||
<textarea
|
<textarea
|
||||||
id="diagnosa"
|
id="diagnosa"
|
||||||
v-model="data.diagnosa"
|
v-model="data.diagnosa"
|
||||||
placeholder="Masukkan Diagnosa"
|
placeholder="Enter Diagnosis"
|
||||||
:class="[
|
:class="[
|
||||||
'textarea bg-white mt-1 min-h-[100px] border',
|
'textarea bg-white mt-1 min-h-[100px] border',
|
||||||
errors.diagnosa
|
errors.diagnosa
|
||||||
|
|
@ -535,8 +533,8 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Jenis Kasus"
|
placeholder="Enter Case Type"
|
||||||
label="Jenis Kasus"
|
label="Case Type"
|
||||||
v-model="data.jenis_kasus"
|
v-model="data.jenis_kasus"
|
||||||
:error="errors.jenis_kasus"
|
:error="errors.jenis_kasus"
|
||||||
:readonly="false"
|
:readonly="false"
|
||||||
|
|
@ -551,12 +549,12 @@ onMounted(() => {
|
||||||
>
|
>
|
||||||
<input type="checkbox" checked />
|
<input type="checkbox" checked />
|
||||||
<div class="collapse-title font-semibold text-base text-dark">
|
<div class="collapse-title font-semibold text-base text-dark">
|
||||||
Tindak Lanjut
|
Follow-up
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse-content">
|
<div class="collapse-content">
|
||||||
<FieldInput
|
<FieldInput
|
||||||
placeholder="Masukkan Tindak Lanjut"
|
placeholder="Enter Follow-up"
|
||||||
label="Tindak Lanjut"
|
label="Follow-up"
|
||||||
list="tindak_lanjut"
|
list="tindak_lanjut"
|
||||||
v-model="data.tindak_lanjut"
|
v-model="data.tindak_lanjut"
|
||||||
:error="errors.tindak_lanjut"
|
:error="errors.tindak_lanjut"
|
||||||
|
|
@ -588,7 +586,7 @@ onMounted(() => {
|
||||||
isLoading ? 'loading loading-spinner loading-xs' : ''
|
isLoading ? 'loading loading-spinner loading-xs' : ''
|
||||||
"
|
"
|
||||||
></span>
|
></span>
|
||||||
{{ isLoading ? "Menyimpan..." : "Simpan Rekam Medis" }}
|
{{ isLoading ? "Saving..." : "Save Medical Record" }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ const fetchLogData = async () => {
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await fetchData();
|
await fetchData();
|
||||||
await fetchLogData();
|
await fetchLogData();
|
||||||
document.title = "Rekam Medis Detail - Hospital Log";
|
document.title = "Medical Record Detail - Hospital Log";
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -107,8 +107,8 @@ onMounted(async () => {
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="Rekam Medis"
|
title="Medical Records"
|
||||||
:subtitle="`Detail Rekam Medis ${route.params.id}`"
|
:subtitle="`Medical Record Detail ${route.params.id}`"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-md text-dark">
|
<div class="bg-white rounded-xl shadow-md text-dark">
|
||||||
|
|
@ -116,64 +116,60 @@ onMounted(async () => {
|
||||||
<div class="breadcrumbs text-sm">
|
<div class="breadcrumbs text-sm">
|
||||||
<ul>
|
<ul>
|
||||||
<li class="font-bold">
|
<li class="font-bold">
|
||||||
<RouterLink to="/rekam-medis">Rekam Medis</RouterLink>
|
<RouterLink to="/rekam-medis">Medical Records</RouterLink>
|
||||||
</li>
|
</li>
|
||||||
<li>Detail Rekam Medis {{ route.params.id }}</li>
|
<li>Medical Record {{ route.params.id }} Detail</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<h5 class="font-bold">Detail Rekam Medis</h5>
|
<h5 class="font-bold">Medical Record Detail</h5>
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p>ID Visit: {{ data?.id_visit }}</p>
|
<p>Visit ID: {{ data?.id_visit }}</p>
|
||||||
<p>Waktu Visit: {{ data?.waktu_visit }}</p>
|
<p>Visit Time: {{ data?.waktu_visit }}</p>
|
||||||
<p>Nomor Rekam Medis: {{ data?.no_rm }}</p>
|
<p>Medical Record Number: {{ data?.no_rm }}</p>
|
||||||
<p>Nama Pasien: {{ data?.nama_pasien }}</p>
|
<p>Patient Name: {{ data?.nama_pasien }}</p>
|
||||||
<p>Umur: {{ data?.umur }} tahun</p>
|
<p>Age: {{ data?.umur }} years</p>
|
||||||
<p>
|
<p>
|
||||||
Jenis Kelamin:
|
Gender:
|
||||||
{{ data?.jenis_kelamin == "L" ? "Laki-laki" : "Perempuan" }}
|
{{ data?.jenis_kelamin == "L" ? "Male" : "Female" }}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Golongan Darah:
|
Blood Type:
|
||||||
{{
|
{{ data?.gol_darah !== "-" ? data?.gol_darah : "Unknown" }}
|
||||||
data?.gol_darah !== "-" ? data?.gol_darah : "Belum Diketahui"
|
|
||||||
}}
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Pekerjaan:
|
Occupation:
|
||||||
{{ data?.pekerjaan ? data?.pekerjaan : "-" }}
|
{{ data?.pekerjaan ? data?.pekerjaan : "-" }}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Suku:
|
Ethnicity:
|
||||||
{{ data?.suku ? data?.suku : "-" }}
|
{{ data?.suku ? data?.suku : "-" }}
|
||||||
</p>
|
</p>
|
||||||
<p>Anamnese: {{ data?.anamnese ? data?.anamnese : "-" }}</p>
|
<p>Anamnesis: {{ data?.anamnese ? data?.anamnese : "-" }}</p>
|
||||||
<p>
|
<p>
|
||||||
Kode Diagnosa:
|
Diagnosis Code:
|
||||||
{{ data?.kode_diagnosa ? data?.kode_diagnosa : "-" }}
|
{{ data?.kode_diagnosa ? data?.kode_diagnosa : "-" }}
|
||||||
</p>
|
</p>
|
||||||
<p>Diagnosa: {{ data?.diagnosa ? data?.diagnosa : "-" }}</p>
|
<p>Diagnosis: {{ data?.diagnosa ? data?.diagnosa : "-" }}</p>
|
||||||
<p>Diastolik: {{ data?.diastolik ? data?.diastolik : "-" }}</p>
|
<p>Diastolic: {{ data?.diastolik ? data?.diastolik : "-" }}</p>
|
||||||
<p>Sistolik: {{ data?.sistolik ? data?.sistolik : "-" }}</p>
|
<p>Systolic: {{ data?.sistolik ? data?.sistolik : "-" }}</p>
|
||||||
<p>Nadi: {{ data?.nadi ? data?.nadi : "-" }}</p>
|
<p>Pulse: {{ data?.nadi ? data?.nadi : "-" }}</p>
|
||||||
<p>Nafas: {{ data?.nafas ? data?.nafas : "-" }}</p>
|
<p>Respiration: {{ data?.nafas ? data?.nafas : "-" }}</p>
|
||||||
<p>Suhu: {{ data?.suhu ? data?.suhu : "-" }}</p>
|
<p>Temperature: {{ data?.suhu ? data?.suhu : "-" }}</p>
|
||||||
<p>
|
<p>
|
||||||
Tinggi Badan:
|
Height:
|
||||||
{{ data?.tinggi_badan ? data?.tinggi_badan : "-" }}
|
{{ data?.tinggi_badan ? data?.tinggi_badan : "-" }}
|
||||||
</p>
|
</p>
|
||||||
|
<p>Weight: {{ data?.berat_badan ? data?.berat_badan : "-" }}</p>
|
||||||
<p>
|
<p>
|
||||||
Berat Badan: {{ data?.berat_badan ? data?.berat_badan : "-" }}
|
Case Type: {{ data?.jenis_kasus ? data?.jenis_kasus : "-" }}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Jenis Kasus: {{ data?.jenis_kasus ? data?.jenis_kasus : "-" }}
|
Follow-up Action:
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Tindak Lanjut:
|
|
||||||
{{ data?.tindak_lanjut ? data?.tindak_lanjut : "-" }}
|
{{ data?.tindak_lanjut ? data?.tindak_lanjut : "-" }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<h5 class="font-bold">Log Perubahan</h5>
|
<h5 class="font-bold">Change Log</h5>
|
||||||
<div role="alert" class="alert alert-error" v-if="isTampered">
|
<div role="alert" class="alert alert-error" v-if="isTampered">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|
@ -188,14 +184,14 @@ onMounted(async () => {
|
||||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span>Peringatan! Manipulasi Data Terdeteksi.</span>
|
<span>Warning! Data tampering detected.</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DataTable
|
<DataTable
|
||||||
:data="dataLog"
|
:data="dataLog"
|
||||||
:columns="LOG_TABLE_COLUMNS"
|
:columns="LOG_TABLE_COLUMNS"
|
||||||
:is-loading="api.isLoading.value"
|
:is-loading="api.isLoading.value"
|
||||||
empty-message="Belum terdapat log perubahan"
|
empty-message="No change logs yet"
|
||||||
:is-aksi="false"
|
:is-aksi="false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -283,7 +283,7 @@ const handleDelete = async (item: RekamMedis) => {
|
||||||
await fetchData();
|
await fetchData();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error deleting rekam medis:", error);
|
console.error("Error deleting rekam medis:", error);
|
||||||
alert("Gagal menghapus data rekam medis");
|
alert("Failed to delete medical record");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -359,7 +359,10 @@ onBeforeUnmount(() => {
|
||||||
<div class="bg-light w-full text-dark">
|
<div class="bg-light w-full text-dark">
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader title="Rekam Medis" subtitle="Manajemen Rekam Medis" />
|
<PageHeader
|
||||||
|
title="Medical Records"
|
||||||
|
subtitle="Medical Records Management"
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
class="collapse collapse-arrow bg-white border-white border shadow-sm mb-2"
|
class="collapse collapse-arrow bg-white border-white border shadow-sm mb-2"
|
||||||
>
|
>
|
||||||
|
|
@ -372,7 +375,7 @@ onBeforeUnmount(() => {
|
||||||
<div class="collapse-content text-sm flex flex-col">
|
<div class="collapse-content text-sm flex flex-col">
|
||||||
<div class="flex gap-x-4 items-end">
|
<div class="flex gap-x-4 items-end">
|
||||||
<div>
|
<div>
|
||||||
<label for="id_visit" class="font-bold">ID Visit</label>
|
<label for="id_visit" class="font-bold">Visit ID</label>
|
||||||
<input
|
<input
|
||||||
class="mt-1 border border-gray-200 bg-gray-50 px-3 py-2 rounded-md shadow-sm focus:border-gray-300 focus:bg-gray-100 focus:outline-0 inset-shadow-gray-300 focus:inset-shadow-xs/80"
|
class="mt-1 border border-gray-200 bg-gray-50 px-3 py-2 rounded-md shadow-sm focus:border-gray-300 focus:bg-gray-100 focus:outline-0 inset-shadow-gray-300 focus:inset-shadow-xs/80"
|
||||||
type="text"
|
type="text"
|
||||||
|
|
@ -383,21 +386,19 @@ onBeforeUnmount(() => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="nama_pasien" class="font-bold">Nama Pasien</label>
|
<label for="nama_pasien" class="font-bold">Patient Name</label>
|
||||||
<input
|
<input
|
||||||
class="mt-1 border border-gray-200 bg-gray-50 px-3 py-2 rounded-md shadow-sm focus:border-gray-300 focus:bg-gray-100 focus:outline-0 inset-shadow-gray-300 focus:inset-shadow-xs/80"
|
class="mt-1 border border-gray-200 bg-gray-50 px-3 py-2 rounded-md shadow-sm focus:border-gray-300 focus:bg-gray-100 focus:outline-0 inset-shadow-gray-300 focus:inset-shadow-xs/80"
|
||||||
type="text"
|
type="text"
|
||||||
name="nama_pasien"
|
name="nama_pasien"
|
||||||
id="nama_pasien"
|
id="nama_pasien"
|
||||||
placeholder="Masukkan Nama Pasien"
|
placeholder="Enter Patient Name"
|
||||||
v-model="filter.nama_pasien"
|
v-model="filter.nama_pasien"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-6/12">
|
<div class="w-6/12">
|
||||||
<label for="range_tanggal" class="font-bold"
|
<label for="range_tanggal" class="font-bold">Date Range</label>
|
||||||
>Rentang Tanggal</label
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
popoverTarget="cally-popover1"
|
popoverTarget="cally-popover1"
|
||||||
:class="[
|
:class="[
|
||||||
|
|
@ -413,10 +414,10 @@ onBeforeUnmount(() => {
|
||||||
filter.rentang_tanggal.start && filter.rentang_tanggal.end
|
filter.rentang_tanggal.start && filter.rentang_tanggal.end
|
||||||
? `${new Date(
|
? `${new Date(
|
||||||
filter.rentang_tanggal.start
|
filter.rentang_tanggal.start
|
||||||
).toLocaleDateString("id-ID")} - ${new Date(
|
).toLocaleDateString("en-US")} - ${new Date(
|
||||||
filter.rentang_tanggal.end
|
filter.rentang_tanggal.end
|
||||||
).toLocaleDateString("id-ID")}`
|
).toLocaleDateString("en-US")}`
|
||||||
: "Pilih rentang tanggal"
|
: "Select date range"
|
||||||
}}
|
}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -455,33 +456,29 @@ onBeforeUnmount(() => {
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full px-2 h-full">
|
<div class="w-full px-2 h-full">
|
||||||
<label class="font-bold block mb-4"
|
<label class="font-bold block mb-4"
|
||||||
>Rentang Umur: {{ filter.rentang_umur[0] }} -
|
>Age Range: {{ filter.rentang_umur[0] }} -
|
||||||
{{ filter.rentang_umur[1] }} tahun</label
|
{{ filter.rentang_umur[1] }} years</label
|
||||||
>
|
>
|
||||||
<div ref="ageSliderRef" class="mb-4"></div>
|
<div ref="ageSliderRef" class="mb-4"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-x-4 items-end mt-4">
|
<div class="flex gap-x-4 items-end mt-4">
|
||||||
<div class="h-full">
|
<div class="h-full">
|
||||||
<label for="jenis_kelamin" class="font-bold"
|
<label for="jenis_kelamin" class="font-bold">Gender</label>
|
||||||
>Jenis Kelamin</label
|
|
||||||
>
|
|
||||||
<select
|
<select
|
||||||
v-model="filter.jenis_kelamin"
|
v-model="filter.jenis_kelamin"
|
||||||
class="select bg-white border border-gray-300 mt-1"
|
class="select bg-white border border-gray-300 mt-1"
|
||||||
>
|
>
|
||||||
<option disabled selected value="initial">
|
<option disabled selected value="initial">
|
||||||
Pilih Jenis Kelamin
|
Select Gender
|
||||||
</option>
|
</option>
|
||||||
<option value="laki-laki">Laki-laki</option>
|
<option value="laki-laki">Male</option>
|
||||||
<option value="perempuan">Perempuan</option>
|
<option value="perempuan">Female</option>
|
||||||
<option value="semua">Semua</option>
|
<option value="semua">All</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="h-full">
|
<div class="h-full">
|
||||||
<label for="golongan_darah" class="font-bold"
|
<label for="golongan_darah" class="font-bold">Blood Type</label>
|
||||||
>Golongan Darah</label
|
|
||||||
>
|
|
||||||
<form
|
<form
|
||||||
class="mt-1 flex flex-wrap gap-1 justify-center items-center"
|
class="mt-1 flex flex-wrap gap-1 justify-center items-center"
|
||||||
>
|
>
|
||||||
|
|
@ -507,21 +504,21 @@ onBeforeUnmount(() => {
|
||||||
|
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<label for="kode_diagnosa" class="font-bold"
|
<label for="kode_diagnosa" class="font-bold"
|
||||||
>Kode Diagnosa</label
|
>Diagnosis Code</label
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
class="mt-1 border border-gray-200 bg-gray-50 px-3 py-2 rounded-md shadow-sm focus:border-gray-300 focus:bg-gray-100 focus:outline-0 inset-shadow-gray-300 focus:inset-shadow-xs/80"
|
class="mt-1 border border-gray-200 bg-gray-50 px-3 py-2 rounded-md shadow-sm focus:border-gray-300 focus:bg-gray-100 focus:outline-0 inset-shadow-gray-300 focus:inset-shadow-xs/80"
|
||||||
type="text"
|
type="text"
|
||||||
name="kode_diagnosa"
|
name="kode_diagnosa"
|
||||||
id="kode_diagnosa"
|
id="kode_diagnosa"
|
||||||
placeholder="Masukkan Kode Diagnosa"
|
placeholder="Enter Diagnosis Code"
|
||||||
v-model="filter.kode_diagnosa"
|
v-model="filter.kode_diagnosa"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<fieldset class="fieldset mt-4">
|
<fieldset class="fieldset mt-4">
|
||||||
<label for="tindak_lanjut" class="font-bold text-sm"
|
<label for="tindak_lanjut" class="font-bold text-sm"
|
||||||
>Tindak Lanjut</label
|
>Follow-up Action</label
|
||||||
>
|
>
|
||||||
<form class="flex flex-wrap gap-2 items-center">
|
<form class="flex flex-wrap gap-2 items-center">
|
||||||
<input
|
<input
|
||||||
|
|
@ -555,7 +552,7 @@ onBeforeUnmount(() => {
|
||||||
@click="handleApplyFilter"
|
@click="handleApplyFilter"
|
||||||
class="btn btn-sm bg-dark hover:bg-light hover:text-dark active:inset-shadow-sm active:inset-shadow-black/50"
|
class="btn btn-sm bg-dark hover:bg-light hover:text-dark active:inset-shadow-sm active:inset-shadow-black/50"
|
||||||
>
|
>
|
||||||
Terapkan
|
Apply Filter
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -567,14 +564,14 @@ onBeforeUnmount(() => {
|
||||||
<div class="flex flex-col w-full gap-2 md:flex-row md:items-center">
|
<div class="flex flex-col w-full gap-2 md:flex-row md:items-center">
|
||||||
<SearchInput
|
<SearchInput
|
||||||
v-model="searchRekamMedis"
|
v-model="searchRekamMedis"
|
||||||
placeholder="Cari berdasarkan Nomor Rekam Medis"
|
placeholder="Search by Medical Record Number"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
/>
|
/>
|
||||||
<div class="flex items-center gap-2 md:ml-4">
|
<div class="flex items-center gap-2 md:ml-4">
|
||||||
<SortDropdown
|
<SortDropdown
|
||||||
v-model="sortBy"
|
v-model="sortBy"
|
||||||
:options="SORT_OPTIONS.REKAM_MEDIS"
|
:options="SORT_OPTIONS.REKAM_MEDIS"
|
||||||
label="Urut berdasarkan:"
|
label="Sort by:"
|
||||||
@change="handleSortChange"
|
@change="handleSortChange"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
|
|
@ -602,7 +599,7 @@ onBeforeUnmount(() => {
|
||||||
to="/rekam-medis/tambah"
|
to="/rekam-medis/tambah"
|
||||||
class="btn btn-sm bg-dark text-light hover:bg-light hover:text-dark active:inset-shadow-sm active:inset-shadow-black/50 self-start md:self-auto"
|
class="btn btn-sm bg-dark text-light hover:bg-light hover:text-dark active:inset-shadow-sm active:inset-shadow-black/50 self-start md:self-auto"
|
||||||
>
|
>
|
||||||
Tambah Rekam Medis
|
Add Medical Record
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -625,8 +622,7 @@ onBeforeUnmount(() => {
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span
|
<span
|
||||||
>Data rekam medis berhasil dikirim untuk validasi
|
>Medical record successfully sent for deletion validation</span
|
||||||
penghapusan</span
|
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -635,7 +631,7 @@ onBeforeUnmount(() => {
|
||||||
:data="data"
|
:data="data"
|
||||||
:columns="REKAM_MEDIS_TABLE_COLUMNS"
|
:columns="REKAM_MEDIS_TABLE_COLUMNS"
|
||||||
:is-loading="api.isLoading.value"
|
:is-loading="api.isLoading.value"
|
||||||
empty-message="Tidak ada data rekam medis"
|
empty-message="No medical records available"
|
||||||
@details="handleDetails"
|
@details="handleDetails"
|
||||||
@update="handleUpdate"
|
@update="handleUpdate"
|
||||||
@delete="handleDelete"
|
@delete="handleDelete"
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ const loadRekamMedis = async () => {
|
||||||
errors.value = {};
|
errors.value = {};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to fetch rekam medis:", error);
|
console.error("Failed to fetch rekam medis:", error);
|
||||||
fetchError.value = "Gagal memuat data rekam medis.";
|
fetchError.value = "Failed to load medical record.";
|
||||||
} finally {
|
} finally {
|
||||||
isFetching.value = false;
|
isFetching.value = false;
|
||||||
}
|
}
|
||||||
|
|
@ -347,7 +347,7 @@ watch(
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.title = "Edit Rekam Medis - Hospital Log";
|
document.title = "Edit Medical Record - Hospital Log";
|
||||||
loadRekamMedis();
|
loadRekamMedis();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -357,8 +357,8 @@ onMounted(() => {
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="Rekam Medis"
|
title="Medical Record"
|
||||||
:subtitle="`Edit Rekam Medis ${route.params.id}`"
|
:subtitle="`Edit Medical Record ${route.params.id}`"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-md text-dark">
|
<div class="bg-white rounded-xl shadow-md text-dark">
|
||||||
|
|
@ -366,19 +366,19 @@ onMounted(() => {
|
||||||
<div class="breadcrumbs text-sm">
|
<div class="breadcrumbs text-sm">
|
||||||
<ul>
|
<ul>
|
||||||
<li class="font-bold">
|
<li class="font-bold">
|
||||||
<RouterLink to="/rekam-medis">Rekam Medis</RouterLink>
|
<RouterLink to="/rekam-medis">Medical Records</RouterLink>
|
||||||
</li>
|
</li>
|
||||||
<li>Edit Rekam Medis</li>
|
<li>Edit Medical Record</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<h5 class="font-bold">Edit Rekam Medis</h5>
|
<h5 class="font-bold">Edit Medical Record</h5>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="flex h-screen flex-col justify-center gap-y-2 items-center"
|
class="flex h-screen flex-col justify-center gap-y-2 items-center"
|
||||||
v-if="isFetching"
|
v-if="isFetching"
|
||||||
>
|
>
|
||||||
<span class="loading loading-ring loading-xl"></span>
|
<span class="loading loading-ring loading-xl"></span>
|
||||||
<h5>Mohon tunggu, sedang memuat rekam medis...</h5>
|
<h5>Please wait, loading medical record...</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
|
|
@ -400,7 +400,7 @@ onMounted(() => {
|
||||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span>Berhasil memperbarui rekam medis!</span>
|
<span>Successfully updated medical record!</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="fetchError"
|
v-if="fetchError"
|
||||||
|
|
@ -410,7 +410,7 @@ onMounted(() => {
|
||||||
<RouterLink
|
<RouterLink
|
||||||
class="btn btn-sm bg-dark text-light"
|
class="btn btn-sm bg-dark text-light"
|
||||||
to="/rekam-medis"
|
to="/rekam-medis"
|
||||||
>Kembali ke Rekam Medis</RouterLink
|
>Back to Medical Records</RouterLink
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -419,7 +419,7 @@ onMounted(() => {
|
||||||
v-else-if="isSubmitting"
|
v-else-if="isSubmitting"
|
||||||
>
|
>
|
||||||
<span class="loading loading-ring loading-xl"></span>
|
<span class="loading loading-ring loading-xl"></span>
|
||||||
<h5>Mohon tunggu, sedang memperbarui rekam medis...</h5>
|
<h5>Please wait, updating medical record...</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form v-else @submit.prevent="handleSubmit" class="text-sm">
|
<form v-else @submit.prevent="handleSubmit" class="text-sm">
|
||||||
|
|
@ -432,28 +432,28 @@ onMounted(() => {
|
||||||
<div
|
<div
|
||||||
class="collapse-title font-semibold text-base text-dark"
|
class="collapse-title font-semibold text-base text-dark"
|
||||||
>
|
>
|
||||||
Identitas Pasien
|
Patient Identity
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse-content">
|
<div class="collapse-content">
|
||||||
<FieldInput
|
<FieldInput
|
||||||
placeholder="Masukkan No. Rekam Medis"
|
placeholder="Enter Medical Record Number"
|
||||||
label="No Rekam Medis"
|
label="Medical Record Number"
|
||||||
v-model="data.no_rm"
|
v-model="data.no_rm"
|
||||||
:error="errors.no_rm"
|
:error="errors.no_rm"
|
||||||
:readonly="false"
|
:readonly="false"
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Nama Pasien"
|
placeholder="Enter Patient Name"
|
||||||
label="Nama Pasien"
|
label="Patient Name"
|
||||||
v-model="data.nama_pasien"
|
v-model="data.nama_pasien"
|
||||||
:error="errors.nama_pasien"
|
:error="errors.nama_pasien"
|
||||||
:readonly="false"
|
:readonly="false"
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Umur"
|
placeholder="Enter Age"
|
||||||
label="Umur"
|
label="Age"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.umur"
|
v-model="data.umur"
|
||||||
:error="errors.umur"
|
:error="errors.umur"
|
||||||
|
|
@ -461,7 +461,7 @@ onMounted(() => {
|
||||||
/>
|
/>
|
||||||
<div class="flex flex-col mt-2">
|
<div class="flex flex-col mt-2">
|
||||||
<label for="jenis_kelamin" class="font-bold"
|
<label for="jenis_kelamin" class="font-bold"
|
||||||
>Jenis Kelamin</label
|
>Gender</label
|
||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
v-model="data.jenis_kelamin"
|
v-model="data.jenis_kelamin"
|
||||||
|
|
@ -474,10 +474,10 @@ onMounted(() => {
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<option disabled value="initial">
|
<option disabled value="initial">
|
||||||
Pilih Jenis Kelamin
|
Select Gender
|
||||||
</option>
|
</option>
|
||||||
<option value="laki-laki">Laki-laki</option>
|
<option value="laki-laki">Male</option>
|
||||||
<option value="perempuan">Perempuan</option>
|
<option value="perempuan">Female</option>
|
||||||
</select>
|
</select>
|
||||||
<p
|
<p
|
||||||
v-if="errors.jenis_kelamin"
|
v-if="errors.jenis_kelamin"
|
||||||
|
|
@ -488,7 +488,7 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col mt-2">
|
<div class="flex flex-col mt-2">
|
||||||
<label for="golongan_darah" class="font-bold"
|
<label for="golongan_darah" class="font-bold"
|
||||||
>Golongan Darah</label
|
>Blood Type</label
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="filter mt-1 flex flex-wrap justify-start items-center"
|
class="filter mt-1 flex flex-wrap justify-start items-center"
|
||||||
|
|
@ -520,16 +520,16 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Pekerjaan"
|
placeholder="Enter Occupation"
|
||||||
label="Pekerjaan"
|
label="Occupation"
|
||||||
v-model="data.pekerjaan"
|
v-model="data.pekerjaan"
|
||||||
:error="errors.pekerjaan"
|
:error="errors.pekerjaan"
|
||||||
:readonly="false"
|
:readonly="false"
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Suku"
|
placeholder="Enter Ethnicity"
|
||||||
label="Suku"
|
label="Ethnicity"
|
||||||
v-model="data.suku"
|
v-model="data.suku"
|
||||||
:error="errors.suku"
|
:error="errors.suku"
|
||||||
:readonly="false"
|
:readonly="false"
|
||||||
|
|
@ -546,21 +546,21 @@ onMounted(() => {
|
||||||
<div
|
<div
|
||||||
class="collapse-title font-semibold text-base text-dark"
|
class="collapse-title font-semibold text-base text-dark"
|
||||||
>
|
>
|
||||||
Tanda-Tanda Vital
|
Vital Signs
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse-content">
|
<div class="collapse-content">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4">
|
||||||
<FieldInput
|
<FieldInput
|
||||||
placeholder="Masukkan Nadi (bpm)"
|
placeholder="Enter Pulse (bpm)"
|
||||||
label="Nadi (bpm)"
|
label="Pulse (bpm)"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.nadi"
|
v-model="data.nadi"
|
||||||
:error="errors.nadi"
|
:error="errors.nadi"
|
||||||
:readonly="false"
|
:readonly="false"
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
placeholder="Masukkan Nafas (per menit)"
|
placeholder="Enter Respiration (per minute)"
|
||||||
label="Nafas (per menit)"
|
label="Respiration (per minute)"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.nafas"
|
v-model="data.nafas"
|
||||||
:error="errors.nafas"
|
:error="errors.nafas"
|
||||||
|
|
@ -568,8 +568,8 @@ onMounted(() => {
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Sistolik (mmHg)"
|
placeholder="Enter Systolic (mmHg)"
|
||||||
label="Tekanan Darah Sistolik (mmHg)"
|
label="Systolic Blood Pressure (mmHg)"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.sistolik"
|
v-model="data.sistolik"
|
||||||
:error="errors.sistolik"
|
:error="errors.sistolik"
|
||||||
|
|
@ -577,8 +577,8 @@ onMounted(() => {
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Diastolik (mmHg)"
|
placeholder="Enter Diastolic (mmHg)"
|
||||||
label="Tekanan Darah Diastolik (mmHg)"
|
label="Diastolic Blood Pressure (mmHg)"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.diastolik"
|
v-model="data.diastolik"
|
||||||
:error="errors.diastolik"
|
:error="errors.diastolik"
|
||||||
|
|
@ -586,8 +586,8 @@ onMounted(() => {
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Suhu (°C)"
|
placeholder="Enter Temperature (°C)"
|
||||||
label="Suhu Tubuh (°C)"
|
label="Body Temperature (°C)"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.suhu"
|
v-model="data.suhu"
|
||||||
:error="errors.suhu"
|
:error="errors.suhu"
|
||||||
|
|
@ -595,8 +595,8 @@ onMounted(() => {
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Tinggi Badan (cm)"
|
placeholder="Enter Height (cm)"
|
||||||
label="Tinggi Badan (cm)"
|
label="Height (cm)"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.tinggi_badan"
|
v-model="data.tinggi_badan"
|
||||||
:error="errors.tinggi_badan"
|
:error="errors.tinggi_badan"
|
||||||
|
|
@ -604,8 +604,8 @@ onMounted(() => {
|
||||||
/>
|
/>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Berat Badan (kg)"
|
placeholder="Enter Body Weight (kg)"
|
||||||
label="Berat Badan (kg)"
|
label="Body Weight (kg)"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="data.berat_badan"
|
v-model="data.berat_badan"
|
||||||
:error="errors.berat_badan"
|
:error="errors.berat_badan"
|
||||||
|
|
@ -622,7 +622,7 @@ onMounted(() => {
|
||||||
>
|
>
|
||||||
<input type="checkbox" checked />
|
<input type="checkbox" checked />
|
||||||
<div class="collapse-title font-semibold text-base text-dark">
|
<div class="collapse-title font-semibold text-base text-dark">
|
||||||
Informasi Medis
|
Medical Information
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse-content">
|
<div class="collapse-content">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
|
|
@ -630,7 +630,7 @@ onMounted(() => {
|
||||||
<textarea
|
<textarea
|
||||||
id="anamnese"
|
id="anamnese"
|
||||||
v-model="data.anamnese"
|
v-model="data.anamnese"
|
||||||
placeholder="Masukkan Anamnese"
|
placeholder="Enter Anamnese"
|
||||||
:class="[
|
:class="[
|
||||||
'textarea bg-white mt-1 min-h-[100px] border',
|
'textarea bg-white mt-1 min-h-[100px] border',
|
||||||
errors.anamnese
|
errors.anamnese
|
||||||
|
|
@ -645,18 +645,18 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Kode Diagnosa"
|
placeholder="Enter Diagnosis Code"
|
||||||
label="Kode Diagnosa"
|
label="Diagnosis Code"
|
||||||
v-model="data.kode_diagnosa"
|
v-model="data.kode_diagnosa"
|
||||||
:error="errors.kode_diagnosa"
|
:error="errors.kode_diagnosa"
|
||||||
:readonly="false"
|
:readonly="false"
|
||||||
/>
|
/>
|
||||||
<div class="flex flex-col mt-2">
|
<div class="flex flex-col mt-2">
|
||||||
<label for="diagnosa" class="font-bold">Diagnosa</label>
|
<label for="diagnosa" class="font-bold">Diagnosis</label>
|
||||||
<textarea
|
<textarea
|
||||||
id="diagnosa"
|
id="diagnosa"
|
||||||
v-model="data.diagnosa"
|
v-model="data.diagnosa"
|
||||||
placeholder="Masukkan Diagnosa"
|
placeholder="Enter Diagnosis"
|
||||||
:class="[
|
:class="[
|
||||||
'textarea bg-white mt-1 min-h-[100px] border',
|
'textarea bg-white mt-1 min-h-[100px] border',
|
||||||
errors.diagnosa
|
errors.diagnosa
|
||||||
|
|
@ -671,8 +671,8 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
<FieldInput
|
<FieldInput
|
||||||
class="mt-2"
|
class="mt-2"
|
||||||
placeholder="Masukkan Jenis Kasus"
|
placeholder="Enter Case Type"
|
||||||
label="Jenis Kasus"
|
label="Case Type"
|
||||||
v-model="data.jenis_kasus"
|
v-model="data.jenis_kasus"
|
||||||
:error="errors.jenis_kasus"
|
:error="errors.jenis_kasus"
|
||||||
:readonly="false"
|
:readonly="false"
|
||||||
|
|
@ -685,12 +685,12 @@ onMounted(() => {
|
||||||
>
|
>
|
||||||
<input type="checkbox" checked />
|
<input type="checkbox" checked />
|
||||||
<div class="collapse-title font-semibold text-base text-dark">
|
<div class="collapse-title font-semibold text-base text-dark">
|
||||||
Tindak Lanjut
|
Follow Up
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse-content">
|
<div class="collapse-content">
|
||||||
<FieldInput
|
<FieldInput
|
||||||
placeholder="Masukkan Tindak Lanjut"
|
placeholder="Enter Follow Up"
|
||||||
label="Tindak Lanjut"
|
label="Follow Up"
|
||||||
list="tindak_lanjut"
|
list="tindak_lanjut"
|
||||||
v-model="data.tindak_lanjut"
|
v-model="data.tindak_lanjut"
|
||||||
:error="errors.tindak_lanjut"
|
:error="errors.tindak_lanjut"
|
||||||
|
|
@ -714,7 +714,7 @@ onMounted(() => {
|
||||||
class="btn btn-sm bg-dark text-light"
|
class="btn btn-sm bg-dark text-light"
|
||||||
:disabled="isSubmitting"
|
:disabled="isSubmitting"
|
||||||
>
|
>
|
||||||
Simpan Perubahan
|
Save Changes
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -130,15 +130,13 @@ const handleUpdate = (item: Users) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async (item: Users) => {
|
const handleDelete = async (item: Users) => {
|
||||||
if (
|
if (confirm(`Are you sure you want to delete user "${item.username}"?`)) {
|
||||||
confirm(`Apakah Anda yakin ingin menghapus pengguna "${item.username}"?`)
|
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
await api.delete(`/obat/${item.id}`);
|
await api.delete(`/obat/${item.id}`);
|
||||||
await fetchData();
|
await fetchData();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error deleting obat:", error);
|
console.error("Error deleting obat:", error);
|
||||||
alert("Gagal menghapus data obat");
|
alert("Failed to delete user data");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -182,7 +180,7 @@ onMounted(async () => {
|
||||||
<div class="bg-light w-full text-dark">
|
<div class="bg-light w-full text-dark">
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader title="Users" subtitle="Manajemen Pengguna" />
|
<PageHeader title="Users" subtitle="User Management" />
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-md">
|
<div class="bg-white rounded-xl shadow-md">
|
||||||
<div
|
<div
|
||||||
|
|
@ -191,14 +189,14 @@ onMounted(async () => {
|
||||||
<div class="flex flex-col w-full gap-2 md:flex-row md:items-center">
|
<div class="flex flex-col w-full gap-2 md:flex-row md:items-center">
|
||||||
<SearchInput
|
<SearchInput
|
||||||
v-model="searchUsername"
|
v-model="searchUsername"
|
||||||
placeholder="Cari berdasarkan username"
|
placeholder="Search by username"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
/>
|
/>
|
||||||
<div class="flex items-center gap-2 md:ml-4">
|
<div class="flex items-center gap-2 md:ml-4">
|
||||||
<SortDropdown
|
<SortDropdown
|
||||||
v-model="sortBy"
|
v-model="sortBy"
|
||||||
:options="SORT_OPTIONS.USERS"
|
:options="SORT_OPTIONS.USERS"
|
||||||
label="Urut berdasarkan:"
|
label="Sort by:"
|
||||||
@change="handleSortChange"
|
@change="handleSortChange"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
|
|
@ -226,7 +224,7 @@ onMounted(async () => {
|
||||||
to="/users/add"
|
to="/users/add"
|
||||||
class="btn btn-sm bg-dark text-light hover:bg-light hover:text-dark active:inset-shadow-sm active:inset-shadow-black/50 self-start md:self-auto"
|
class="btn btn-sm bg-dark text-light hover:bg-light hover:text-dark active:inset-shadow-sm active:inset-shadow-black/50 self-start md:self-auto"
|
||||||
>
|
>
|
||||||
Tambah Pengguna
|
Add User
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -235,7 +233,7 @@ onMounted(async () => {
|
||||||
:data="data"
|
:data="data"
|
||||||
:columns="USERS_TABLE_COLUMNS"
|
:columns="USERS_TABLE_COLUMNS"
|
||||||
:is-loading="api.isLoading.value"
|
:is-loading="api.isLoading.value"
|
||||||
empty-message="Tidak ada data pengguna"
|
empty-message="No user data"
|
||||||
@details="handleDetails"
|
@details="handleDetails"
|
||||||
@update="handleUpdate"
|
@update="handleUpdate"
|
||||||
@delete="handleDelete"
|
@delete="handleDelete"
|
||||||
|
|
|
||||||
|
|
@ -182,15 +182,15 @@ const showRejectDialog = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const tableLabelMap: Record<string, string> = {
|
const tableLabelMap: Record<string, string> = {
|
||||||
pemberian_obat: "Pemberian Obat",
|
pemberian_obat: "Medicine Administration",
|
||||||
pemberian_tindakan: "Pemberian Tindakan",
|
pemberian_tindakan: "Doctor Actions",
|
||||||
rekam_medis: "Rekam Medis",
|
rekam_medis: "Medical Records",
|
||||||
};
|
};
|
||||||
|
|
||||||
const actionLabelMap: Record<string, string> = {
|
const actionLabelMap: Record<string, string> = {
|
||||||
CREATE: "Tambah Data",
|
CREATE: "Add Data",
|
||||||
UPDATE: "Ubah Data",
|
UPDATE: "Edit Data",
|
||||||
DELETE: "Hapus Data",
|
DELETE: "Delete Data",
|
||||||
};
|
};
|
||||||
|
|
||||||
const statusBadgeClass = computed(() => {
|
const statusBadgeClass = computed(() => {
|
||||||
|
|
@ -235,22 +235,22 @@ const handleApprove = async () => {
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
console.log("Approve response:", response);
|
console.log("Approve response:", response);
|
||||||
alert("Permintaan berhasil disetujui");
|
alert("Request successfully approved");
|
||||||
router.push({ name: "validasi" });
|
router.push({ name: "validasi" });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error approving validation:", error);
|
console.error("Error approving validation:", error);
|
||||||
alert("Gagal menyetujui permintaan");
|
alert("Failed to approve request");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleReject = async () => {
|
const handleReject = async () => {
|
||||||
try {
|
try {
|
||||||
await api.post(`/validation/${route.params.id}/reject`, {});
|
await api.post(`/validation/${route.params.id}/reject`, {});
|
||||||
alert("Permintaan berhasil ditolak");
|
alert("Request successfully rejected");
|
||||||
router.push({ name: "validasi" });
|
router.push({ name: "validasi" });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error rejecting validation:", error);
|
console.error("Error rejecting validation:", error);
|
||||||
alert("Gagal menolak permintaan");
|
alert("Failed to reject request");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -276,7 +276,7 @@ const formatTimestamp = (rawValue?: string) => {
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await fetchData();
|
await fetchData();
|
||||||
document.title = `Review Validasi - ID ${route.params.id}`;
|
document.title = `Review Validation - ID ${route.params.id}`;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -285,8 +285,8 @@ onMounted(async () => {
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="Validasi"
|
title="Validation"
|
||||||
:subtitle="`Review Permintaan Validasi ${route.params.id}`"
|
:subtitle="`Review Validation Request ${route.params.id}`"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-md text-dark">
|
<div class="bg-white rounded-xl shadow-md text-dark">
|
||||||
|
|
@ -294,49 +294,51 @@ onMounted(async () => {
|
||||||
<div class="breadcrumbs text-sm">
|
<div class="breadcrumbs text-sm">
|
||||||
<ul>
|
<ul>
|
||||||
<li class="font-bold">
|
<li class="font-bold">
|
||||||
<RouterLink to="/validasi"> Validasi </RouterLink>
|
<RouterLink to="/validasi"> Validation </RouterLink>
|
||||||
</li>
|
</li>
|
||||||
<li>Review Permintaan {{ route.params.id }}</li>
|
<li>Review Request {{ route.params.id }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<h5 class="font-bold">Detail Permintaan Validasi</h5>
|
<h5 class="font-bold">Validation Request Details</h5>
|
||||||
<span class="badge" :class="statusBadgeClass">
|
<span class="badge" :class="statusBadgeClass">
|
||||||
{{ validation?.status }}
|
{{ validation?.status }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<p><strong>ID Permintaan:</strong> {{ validation?.id }}</p>
|
|
||||||
<p>
|
<p>
|
||||||
<strong>Tabel:</strong>
|
<strong>Validation Request ID:</strong> {{ validation?.id }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Table:</strong>
|
||||||
{{
|
{{
|
||||||
tableLabelMap[validation?.table_name || ""] ||
|
tableLabelMap[validation?.table_name || ""] ||
|
||||||
validation?.table_name
|
validation?.table_name
|
||||||
}}
|
}}
|
||||||
</p>
|
</p>
|
||||||
<p><strong>ID Record:</strong> {{ validation?.record_id }}</p>
|
<p><strong>Record ID:</strong> {{ validation?.record_id }}</p>
|
||||||
<p>
|
<p>
|
||||||
<strong>Aksi:</strong>
|
<strong>Action:</strong>
|
||||||
{{
|
{{
|
||||||
actionLabelMap[validation?.action || ""] || validation?.action
|
actionLabelMap[validation?.action || ""] || validation?.action
|
||||||
}}
|
}}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<strong>Pemohon:</strong> User ID
|
<strong>Requester:</strong> User ID
|
||||||
{{ validation?.user_id_request }}
|
{{ validation?.user_id_request }}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<strong>Diajukan:</strong>
|
<strong>Submitted:</strong>
|
||||||
{{ formatTimestamp(validation?.created_at) }}
|
{{ formatTimestamp(validation?.created_at) }}
|
||||||
</p>
|
</p>
|
||||||
<p v-if="validation?.processed_at">
|
<p v-if="validation?.processed_at">
|
||||||
<strong>Diproses:</strong>
|
<strong>Processed:</strong>
|
||||||
{{ formatTimestamp(validation?.processed_at) }}
|
{{ formatTimestamp(validation?.processed_at) }}
|
||||||
</p>
|
</p>
|
||||||
<p v-if="validation?.user_id_process">
|
<p v-if="validation?.user_id_process">
|
||||||
<strong>Diproses oleh:</strong> User ID
|
<strong>Processed by:</strong> User ID
|
||||||
{{ validation?.user_id_process }}
|
{{ validation?.user_id_process }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -364,7 +366,7 @@ onMounted(async () => {
|
||||||
<div
|
<div
|
||||||
class="bg-white border border-dark rounded-lg p-4 text-sm overflow-x-auto flex-1"
|
class="bg-white border border-dark rounded-lg p-4 text-sm overflow-x-auto flex-1"
|
||||||
>
|
>
|
||||||
<h1 class="font-bold mb-2">Data Sebelum</h1>
|
<h1 class="font-bold mb-2">Before Data</h1>
|
||||||
<pre
|
<pre
|
||||||
class="whitespace-pre-wrap"
|
class="whitespace-pre-wrap"
|
||||||
v-html="formatJsonWithHighlight(previousLog, 'old')"
|
v-html="formatJsonWithHighlight(previousLog, 'old')"
|
||||||
|
|
@ -373,7 +375,7 @@ onMounted(async () => {
|
||||||
<div
|
<div
|
||||||
class="bg-white border border-dark rounded-lg p-4 text-sm overflow-x-auto flex-1"
|
class="bg-white border border-dark rounded-lg p-4 text-sm overflow-x-auto flex-1"
|
||||||
>
|
>
|
||||||
<h1 class="font-bold mb-2">Data Sesudah</h1>
|
<h1 class="font-bold mb-2">After Data</h1>
|
||||||
<pre
|
<pre
|
||||||
class="whitespace-pre-wrap"
|
class="whitespace-pre-wrap"
|
||||||
v-html="formatJsonWithHighlight(normalizedNewPayload, 'new')"
|
v-html="formatJsonWithHighlight(normalizedNewPayload, 'new')"
|
||||||
|
|
@ -389,13 +391,13 @@ onMounted(async () => {
|
||||||
type="button"
|
type="button"
|
||||||
@click="showApproveDialog"
|
@click="showApproveDialog"
|
||||||
:disabled="api.isLoading.value"
|
:disabled="api.isLoading.value"
|
||||||
text="Setujui"
|
text="Approve"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
@click="showRejectDialog"
|
@click="showRejectDialog"
|
||||||
class="bg-white btn btn-sm text-dark"
|
class="bg-white btn btn-sm text-dark"
|
||||||
>
|
>
|
||||||
Tolak
|
Reject
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -403,19 +405,19 @@ onMounted(async () => {
|
||||||
|
|
||||||
<DialogConfirm
|
<DialogConfirm
|
||||||
ref="approveDialog"
|
ref="approveDialog"
|
||||||
title="Setujui Permintaan"
|
title="Approve Request"
|
||||||
message="Apakah Anda yakin ingin menyetujui permintaan validasi ini?"
|
message="Are you sure you want to approve this validation request?"
|
||||||
confirm-text="Ya, Setujui"
|
confirm-text="Yes, Approve"
|
||||||
cancel-text="Batal"
|
cancel-text="Cancel"
|
||||||
@confirm="handleApprove"
|
@confirm="handleApprove"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DialogConfirm
|
<DialogConfirm
|
||||||
ref="rejectDialog"
|
ref="rejectDialog"
|
||||||
title="Tolak Permintaan"
|
title="Reject Request"
|
||||||
message="Apakah Anda yakin ingin menolak permintaan validasi ini?"
|
message="Are you sure you want to reject this validation request?"
|
||||||
confirm-text="Ya, Tolak"
|
confirm-text="Yes, Reject"
|
||||||
cancel-text="Batal"
|
cancel-text="Cancel"
|
||||||
@confirm="handleReject"
|
@confirm="handleReject"
|
||||||
/>
|
/>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
|
|
||||||
|
|
@ -83,11 +83,11 @@ const normalizedData = (rawData: any[]): ValidationLog[] => {
|
||||||
const formattedTableName = (tableName: string): string => {
|
const formattedTableName = (tableName: string): string => {
|
||||||
switch (tableName) {
|
switch (tableName) {
|
||||||
case "rekam_medis":
|
case "rekam_medis":
|
||||||
return "Rekam Medis";
|
return "Medical Records";
|
||||||
case "pemberian_tindakan":
|
case "pemberian_tindakan":
|
||||||
return "Tindakan Dokter";
|
return "Doctor Actions";
|
||||||
case "pemberian_obat":
|
case "pemberian_obat":
|
||||||
return "Obat";
|
return "Medicine";
|
||||||
default:
|
default:
|
||||||
return tableName;
|
return tableName;
|
||||||
}
|
}
|
||||||
|
|
@ -115,7 +115,7 @@ const normalizedData = (rawData: any[]): ValidationLog[] => {
|
||||||
if (isNaN(date.getTime())) {
|
if (isNaN(date.getTime())) {
|
||||||
return dateString;
|
return dateString;
|
||||||
}
|
}
|
||||||
return date.toLocaleString("id-ID", {
|
return date.toLocaleString("en-US", {
|
||||||
timeZone: "Asia/Jakarta",
|
timeZone: "Asia/Jakarta",
|
||||||
day: "2-digit",
|
day: "2-digit",
|
||||||
month: "2-digit",
|
month: "2-digit",
|
||||||
|
|
@ -132,7 +132,7 @@ const normalizedData = (rawData: any[]): ValidationLog[] => {
|
||||||
if (isNaN(date.getTime())) {
|
if (isNaN(date.getTime())) {
|
||||||
return dateString;
|
return dateString;
|
||||||
}
|
}
|
||||||
return date.toLocaleString("id-ID", {
|
return date.toLocaleString("en-US", {
|
||||||
timeZone: "Asia/Jakarta",
|
timeZone: "Asia/Jakarta",
|
||||||
day: "2-digit",
|
day: "2-digit",
|
||||||
month: "2-digit",
|
month: "2-digit",
|
||||||
|
|
@ -228,13 +228,13 @@ const handleUpdate = (item: ValidationLog) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async (item: ValidationLog) => {
|
const handleDelete = async (item: ValidationLog) => {
|
||||||
if (confirm(`Apakah Anda yakin ingin menghapus item "${item.id}"?`)) {
|
if (confirm(`Are you sure you want to delete item "${item.id}"?`)) {
|
||||||
try {
|
try {
|
||||||
await api.delete(`/validation/${item.id}`);
|
await api.delete(`/validation/${item.id}`);
|
||||||
await fetchData();
|
await fetchData();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error deleting validation:", error);
|
console.error("Error deleting validation:", error);
|
||||||
alert("Gagal menghapus data validasi");
|
alert("Failed to delete validation data");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -302,7 +302,7 @@ onMounted(async () => {
|
||||||
<div class="bg-light w-full text-dark">
|
<div class="bg-light w-full text-dark">
|
||||||
<div class="flex h-full p-2">
|
<div class="flex h-full p-2">
|
||||||
<Sidebar>
|
<Sidebar>
|
||||||
<PageHeader title="Validasi" subtitle="Manajemen Validasi" />
|
<PageHeader title="Validation" subtitle="Validation Management" />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="collapse collapse-arrow bg-white border-white border shadow-sm mb-2"
|
class="collapse collapse-arrow bg-white border-white border shadow-sm mb-2"
|
||||||
|
|
@ -318,57 +318,59 @@ onMounted(async () => {
|
||||||
<div class="flex gap-x-4 items-end">
|
<div class="flex gap-x-4 items-end">
|
||||||
<div class="h-full">
|
<div class="h-full">
|
||||||
<label for="jenis_kelamin" class="font-bold"
|
<label for="jenis_kelamin" class="font-bold"
|
||||||
>Kelompok Data</label
|
>Data Group</label
|
||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
v-model="filters.kelompok_data"
|
v-model="filters.kelompok_data"
|
||||||
class="select bg-white border border-gray-300 mt-1"
|
class="select bg-white border border-gray-300 mt-1"
|
||||||
>
|
>
|
||||||
<option disabled selected value="initial">
|
<option disabled selected value="initial">
|
||||||
Pilih Kelompok Data
|
Select Data Group
|
||||||
</option>
|
</option>
|
||||||
<option value="rekam_medis">Rekam Medis</option>
|
<option value="rekam_medis">Medical Records</option>
|
||||||
<option value="pemberian_tindakan">Tindakan</option>
|
<option value="pemberian_tindakan">Doctor Actions</option>
|
||||||
<option value="pemberian_obat">Obat</option>
|
<option value="pemberian_obat">
|
||||||
<option value="all">Semua Tipe</option>
|
Medicine Administration
|
||||||
|
</option>
|
||||||
|
<option value="all">All Types</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-x-4 items-end">
|
<div class="flex gap-x-4 items-end">
|
||||||
<div class="h-full">
|
<div class="h-full">
|
||||||
<label for="jenis_kelamin" class="font-bold"
|
<label for="jenis_kelamin" class="font-bold"
|
||||||
>Jenis Aksi</label
|
>Action Type</label
|
||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
v-model="filters.aksi"
|
v-model="filters.aksi"
|
||||||
class="select bg-white border border-gray-300 mt-1"
|
class="select bg-white border border-gray-300 mt-1"
|
||||||
>
|
>
|
||||||
<option disabled selected value="initial">
|
<option disabled selected value="initial">
|
||||||
Pilih Jenis Aksi
|
Select Action Type
|
||||||
</option>
|
</option>
|
||||||
<option value="CREATE">Create</option>
|
<option value="CREATE">Create</option>
|
||||||
<option value="UPDATE">Update</option>
|
<option value="UPDATE">Update</option>
|
||||||
<option value="DELETE">Delete</option>
|
<option value="DELETE">Delete</option>
|
||||||
<option value="all">Semua</option>
|
<option value="all">All</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-x-4 items-end">
|
<div class="flex gap-x-4 items-end">
|
||||||
<div class="h-full">
|
<div class="h-full">
|
||||||
<label for="jenis_kelamin" class="font-bold"
|
<label for="jenis_kelamin" class="font-bold"
|
||||||
>Status Validasi</label
|
>Validation Status</label
|
||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
v-model="filters.status"
|
v-model="filters.status"
|
||||||
class="select bg-white border border-gray-300 mt-1"
|
class="select bg-white border border-gray-300 mt-1"
|
||||||
>
|
>
|
||||||
<option disabled selected value="initial">
|
<option disabled selected value="initial">
|
||||||
Pilih Status Validasi
|
Select Validation Status
|
||||||
</option>
|
</option>
|
||||||
<option value="PENDING">Pending</option>
|
<option value="PENDING">Pending</option>
|
||||||
<option value="APPROVED">Approved</option>
|
<option value="APPROVED">Approved</option>
|
||||||
<option value="REJECTED">Rejected</option>
|
<option value="REJECTED">Rejected</option>
|
||||||
<option value="all">Semua</option>
|
<option value="all">All</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -391,14 +393,14 @@ onMounted(async () => {
|
||||||
<div class="flex flex-col w-full gap-2 md:flex-row md:items-center">
|
<div class="flex flex-col w-full gap-2 md:flex-row md:items-center">
|
||||||
<SearchInput
|
<SearchInput
|
||||||
v-model="searchId"
|
v-model="searchId"
|
||||||
placeholder="Cari berdasarkan ID Record"
|
placeholder="Search by Record ID"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
/>
|
/>
|
||||||
<div class="flex items-center gap-2 md:ml-4">
|
<div class="flex items-center gap-2 md:ml-4">
|
||||||
<SortDropdown
|
<SortDropdown
|
||||||
v-model="sortBy"
|
v-model="sortBy"
|
||||||
:options="SORT_OPTIONS.VALIDATION"
|
:options="SORT_OPTIONS.VALIDATION"
|
||||||
label="Urut berdasarkan:"
|
label="Sort by:"
|
||||||
@change="handleSortChange"
|
@change="handleSortChange"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
|
|
@ -429,7 +431,7 @@ onMounted(async () => {
|
||||||
:data="data"
|
:data="data"
|
||||||
:columns="VALIDATION_TABLE_COLUMNS"
|
:columns="VALIDATION_TABLE_COLUMNS"
|
||||||
:is-loading="api.isLoading.value"
|
:is-loading="api.isLoading.value"
|
||||||
empty-message="Tidak ada data validasi"
|
empty-message="No validation data available"
|
||||||
@details="handleDetails"
|
@details="handleDetails"
|
||||||
@update="handleUpdate"
|
@update="handleUpdate"
|
||||||
@delete="handleDelete"
|
@delete="handleDelete"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user