feat(ProductSerialPage, SerialItemCard, ProductListPage, ProductCard): slicing UI Product Serial Sage, update UI Product List Page
This commit is contained in:
BIN
src/assets/images/calendar.png
Normal file
BIN
src/assets/images/calendar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
BIN
src/assets/images/tools.png
Normal file
BIN
src/assets/images/tools.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
@@ -5,3 +5,17 @@
|
|||||||
.bg-transparent {
|
.bg-transparent {
|
||||||
--background: transparent;
|
--background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.shallow-bow {
|
||||||
|
border-radius: 100% 100% 0 0;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 150%;
|
||||||
|
height: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shallow-bow-container {
|
||||||
|
@apply h-max min-h-full relative bg-sky-50 bg-opacity-50 max-w-full overflow-hidden;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<ion-card button @click="$router.push('/products/'+product.id)" :class="product.stock ? 'bg-blue-50 border-blue-100' : 'bg-red-50 border-red-100'"
|
<ion-card button @click="router.push('/products/'+product.id)" :class="product.stock ? 'bg-blue-50 border-blue-100' : 'bg-red-50 border-red-100'"
|
||||||
class="rounded-2xl border m-0 aspect-square relative">
|
class="rounded-2xl border m-0 aspect-square relative">
|
||||||
<div class="h-full w-full flex flex-col justify-between items-center absolute p-4">
|
<div class="h-full w-full flex flex-col justify-between items-center absolute p-4">
|
||||||
<div class="flex-1 flex items-center">
|
<div class="flex-1 flex items-center">
|
||||||
@@ -24,4 +24,8 @@ import { IonCard } from '@ionic/vue'
|
|||||||
defineProps({
|
defineProps({
|
||||||
product: Object
|
product: Object
|
||||||
})
|
})
|
||||||
|
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
</script>
|
</script>
|
||||||
88
src/components/product/SerialItemCard.vue
Normal file
88
src/components/product/SerialItemCard.vue
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<template>
|
||||||
|
<ion-card
|
||||||
|
:class="item.status === 'used' ? 'bg-blue-50 border-blue-100' : item.status === 'ready' ? 'bg-lime-50 border-lime-100' : 'bg-red-50 border-red-100'"
|
||||||
|
class="rounded-2xl border m-0">
|
||||||
|
<div class="h-full w-full p-4 space-y-2">
|
||||||
|
<div class="flex justify-between gap-2">
|
||||||
|
<div class="flex flex-col items-center w-full">
|
||||||
|
<div>No Seri</div>
|
||||||
|
<div
|
||||||
|
class="h-fit font-medium p-1 rounded-full bg-white w-full max-w-52 flex items-center justify-center border text-black">
|
||||||
|
{{ item.serial }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col items-center w-full">
|
||||||
|
<div>Lokasi</div>
|
||||||
|
<div
|
||||||
|
class="h-fit font-medium p-1 rounded-full bg-white w-full max-w-52 flex items-center justify-center border text-black">
|
||||||
|
{{ item.location }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-between gap-2">
|
||||||
|
<div class="flex flex-col items-center w-full">
|
||||||
|
<div>Waktu Produksi</div>
|
||||||
|
<div
|
||||||
|
class="h-fit font-medium p-1 rounded-full bg-white w-full max-w-52 flex items-center justify-center border text-black">
|
||||||
|
{{ item.production }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col items-center w-full">
|
||||||
|
<div>Status</div>
|
||||||
|
<div class="h-fit font-medium p-0 rounded-full bg-white w-full max-w-52 flex items-center border relative">
|
||||||
|
<div class="w-5 max-h-full aspect-square rounded-full absolute left-[6px]"
|
||||||
|
:class="item.status === 'ready' ? 'bg-green-500' : item.status === 'used' ? 'bg-blue-500' : 'bg-red-500'">
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 py-1 px-5 text-black text-center">
|
||||||
|
{{ item.status === 'ready' ? 'Ready to use' : item.status === 'used' ? 'Digunakan' : 'Maintenance' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div :class="item.status === 'ready' && 'invisible'" class="grid grid-cols-2 gap-2 w-full">
|
||||||
|
<div :class="item.status === 'maintenance' && 'invisible'" class="flex flex-col items-center">
|
||||||
|
<div class="grid grid-cols-7 items-center w-full max-w-52 px-2">
|
||||||
|
<img src="@/assets/images/tools.png" alt="Icon tools" class="w-max aspect-square">
|
||||||
|
<div class="col-span-6 h-max font-medium flex flex-col items-center">
|
||||||
|
<div>History</div>
|
||||||
|
<div class="text-black">
|
||||||
|
{{ item.history }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<div class="grid grid-cols-7 items-center w-full max-w-52 px-2">
|
||||||
|
<img src="@/assets/images/calendar.png" alt="Icon calendar" class="w-max aspect-square">
|
||||||
|
<div class="col-span-6 h-max font-medium flex flex-col items-center">
|
||||||
|
<div>Installation</div>
|
||||||
|
<div class="text-black">
|
||||||
|
{{ item.installation }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ion-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { IonCard } from '@ionic/vue'
|
||||||
|
defineProps({
|
||||||
|
item: {
|
||||||
|
type: {
|
||||||
|
serial: String,
|
||||||
|
production: String,
|
||||||
|
status: String,
|
||||||
|
location: String,
|
||||||
|
installation: String,
|
||||||
|
history: String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<ion-split-pane content-id="main-content" when="md">
|
<ion-split-pane content-id="main-content" when="md">
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<AppSidebar />
|
<!-- <AppSidebar /> -->
|
||||||
|
|
||||||
<!-- Main Area -->
|
<!-- Main Area -->
|
||||||
<ion-page id="main-content">
|
<ion-page id="main-content">
|
||||||
<AppHeader />
|
<!-- <AppHeader /> -->
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<ion-router-outlet class="overflow-auto" />
|
<ion-router-outlet class="overflow-auto" />
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { createRouter, createWebHistory } from '@ionic/vue-router';
|
|||||||
import { RouteRecordRaw } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
import HomePage from '@/views/home/HomePage.vue'
|
import HomePage from '@/views/home/HomePage.vue'
|
||||||
import ProductListPage from '@/views/product/ProductListPage.vue';
|
import ProductListPage from '@/views/product/ProductListPage.vue';
|
||||||
import ProductDetailPage from '@/views/product/ProductDetailPage.vue';
|
import ProductSerialPage from '@/views/product/ProductSerialPage.vue';
|
||||||
import MainLayout from '@/layouts/MainLayout.vue'
|
import MainLayout from '@/layouts/MainLayout.vue'
|
||||||
|
|
||||||
const routes: Array<RouteRecordRaw> = [
|
const routes: Array<RouteRecordRaw> = [
|
||||||
@@ -26,8 +26,8 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'products/:id',
|
path: 'products/:id',
|
||||||
name: 'Products Details',
|
name: 'Products Serials',
|
||||||
component: ProductDetailPage
|
component: ProductSerialPage
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
<template>
|
|
||||||
<ion-page>
|
|
||||||
<ion-content class="ion-padding">
|
|
||||||
|
|
||||||
<ion-button fill="clear" @click="$router.back()">
|
|
||||||
<ion-icon slot="start" :icon="returnUpBack"></ion-icon>
|
|
||||||
Kembali
|
|
||||||
</ion-button>
|
|
||||||
|
|
||||||
<h2 class="text-xl font-bold mb-4">APM CLOPPY</h2>
|
|
||||||
|
|
||||||
<ion-card v-for="item in serials" :key="item.serial" class="mb-4 p-3 rounded-xl shadow-sm">
|
|
||||||
|
|
||||||
<div class="flex justify-between mb-2">
|
|
||||||
<div>
|
|
||||||
<p class="text-sm text-gray-500">No Seri</p>
|
|
||||||
<p class="font-semibold">{{ item.serial }}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<StatusBadge :status="item.status" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-sm text-gray-600 space-y-1">
|
|
||||||
<p><strong>Waktu Produksi:</strong> {{ item.production }}</p>
|
|
||||||
<p><strong>Lokasi:</strong> {{ item.location }}</p>
|
|
||||||
<p><strong>Installation:</strong> {{ item.installation }}</p>
|
|
||||||
<p><strong>History:</strong> {{ item.history }}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</ion-card>
|
|
||||||
|
|
||||||
</ion-content>
|
|
||||||
</ion-page>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { IonPage, IonContent, IonCard, IonButton } from '@ionic/vue'
|
|
||||||
import StatusBadge from '@/components/common/StatusBadge.vue'
|
|
||||||
import { returnUpBack } from 'ionicons/icons'
|
|
||||||
|
|
||||||
const serials = [
|
|
||||||
{
|
|
||||||
serial: 'APM001 INT',
|
|
||||||
production: '04-02-2026',
|
|
||||||
status: 'Digunakan',
|
|
||||||
location: 'Dusun Bambu',
|
|
||||||
installation: '03-04-2026',
|
|
||||||
history: '2x Maintenance'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
serial: 'APM004 INT',
|
|
||||||
production: '12-03-2026',
|
|
||||||
status: 'Maintenance',
|
|
||||||
location: 'Park Zoo',
|
|
||||||
installation: '03-04-2026',
|
|
||||||
history: '1x Maintenance'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
</script>
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<ion-page class="overflow-auto h-max min-h-full">
|
<ion-page class="shallow-bow-container">
|
||||||
<ion-content>
|
<!-- Background -->
|
||||||
<div class="relative bg-sky-50 bg-opacity-50 h-max min-h-full">
|
<div class="bg-neutral-900 shallow-bow">
|
||||||
<!-- Background -->
|
</div>
|
||||||
<div class="bg-neutral-900 shallow-bow">
|
<ion-content class="bg-transparent">
|
||||||
</div>
|
<div class="h-max min-h-full">
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<div class="flex flex-col items-center aspect-auto mt-4">
|
<div class="flex flex-col items-center aspect-auto mt-4">
|
||||||
<img src="@/assets/images/Logo-KDM-merah.png" alt="Logo KDM" class="w-[20%]">
|
<img src="@/assets/images/Logo-KDM-merah.png" alt="Logo KDM" class="w-[20%]">
|
||||||
@@ -28,15 +28,16 @@
|
|||||||
</ion-card>
|
</ion-card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ion-card button color="danger" class="bg-red-500 p-2 text-sm rounded-full">
|
<ion-card button color="danger" class="bg-red-500 p-2 m-4 text-sm rounded-full">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center relative h-max">
|
||||||
<div class="w-14 aspect-square rounded-full bg-white flex items-center justify-center p-2">
|
<div
|
||||||
|
class="h-full aspect-square rounded-full bg-white flex items-center justify-center p-2 absolute left-0">
|
||||||
<img src="@/assets/images/KDM.png" alt="Logo KDM small" class="h-full">
|
<img src="@/assets/images/KDM.png" alt="Logo KDM small" class="h-full">
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1 text-xl text-center font-semibold">LOGIN DASHBOARD</div>
|
<div class="flex-1 text-xl text-center font-semibold p-3">LOGIN DASHBOARD</div>
|
||||||
</div>
|
</div>
|
||||||
</ion-card>
|
</ion-card>
|
||||||
<AppFooter />
|
<AppFooter color="white" />
|
||||||
</div>
|
</div>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
</ion-page>
|
</ion-page>
|
||||||
@@ -56,16 +57,3 @@ const products = [
|
|||||||
{ id: 6, name: 'MESIN ABSENSI', stock: 2 }
|
{ id: 6, name: 'MESIN ABSENSI', stock: 2 }
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.shallow-bow {
|
|
||||||
border-radius: 100% 100% 0 0;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
width: 150%;
|
|
||||||
height: 60%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
104
src/views/product/ProductSerialPage.vue
Normal file
104
src/views/product/ProductSerialPage.vue
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<template>
|
||||||
|
<ion-page class="shallow-bow-container">
|
||||||
|
<!-- Background -->
|
||||||
|
<div class="bg-red-500 shallow-bow">
|
||||||
|
</div>
|
||||||
|
<ion-content class="bg-transparent">
|
||||||
|
<div class="h-max min-h-full">
|
||||||
|
<div class="p-4">
|
||||||
|
<div class="flex items-center justify-between w-full aspect-auto mb-6 mt-4">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<ion-button size="medium" fill="clear" color="dark" @click="router.back()">
|
||||||
|
<div class="font-semibold flex items-center gap-2">
|
||||||
|
<ion-icon slot="icon-only" :icon="caretBackCircleSharp" class="text-2xl"></ion-icon>
|
||||||
|
<div>Kembali</div>
|
||||||
|
</div>
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
<img src="@/assets/images/Logo-KDM-merah.png" alt="Logo KDM" class="w-[20%] cursor-pointer" button
|
||||||
|
@click="router.push('/')">
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-1 gap-4">
|
||||||
|
<ion-searchbar mode="ios" :animated="true" placeholder="No Seri Produk"
|
||||||
|
class="border-2 shadow-sm rounded-full bg-transparent my-6 bg-white"></ion-searchbar>
|
||||||
|
|
||||||
|
<div class="flex gap-2 items-end justify-between mb-2">
|
||||||
|
<h2 class="text-2xl font-semibold">APM CLOPPY</h2>
|
||||||
|
<div class="flex gap-2 items-center justify-between text-gray-500">
|
||||||
|
<div>Detail informasi</div>
|
||||||
|
<ion-button size="small" fill="clear" class="text-gray-500 rounded-md">
|
||||||
|
<ion-icon slot="icon-only" :icon="funnelOutline"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ion-card class="rounded-2xl m-0 border-2 shadow-sm">
|
||||||
|
<ion-card-content class="ion-padding">
|
||||||
|
<div class="grid grid-cols-1 gap-4">
|
||||||
|
<div size="6" size-md="3" v-for="(item) in serialItems" :key="item.id">
|
||||||
|
<SerialItemCard :item="item" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ion-card-content>
|
||||||
|
</ion-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ion-card button color="danger" class="bg-neutral-900 p-2 m-4 text-sm rounded-full">
|
||||||
|
<div class="flex items-center relative h-max">
|
||||||
|
<div
|
||||||
|
class="h-full aspect-square rounded-full bg-white flex items-center justify-center p-2 absolute left-0">
|
||||||
|
<img src="@/assets/images/KDM.png" alt="Logo KDM small" class="h-full">
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 text-xl text-center font-semibold p-3">LOGIN DASHBOARD</div>
|
||||||
|
</div>
|
||||||
|
</ion-card>
|
||||||
|
<AppFooter color="white" />
|
||||||
|
</div>
|
||||||
|
</ion-content>
|
||||||
|
</ion-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { IonPage, IonContent, IonSearchbar, IonCard, IonCardContent, IonIcon, IonButton } from '@ionic/vue'
|
||||||
|
import AppFooter from '@/components/common/AppFooter.vue'
|
||||||
|
import SerialItemCard from '@/components/product/SerialItemCard.vue'
|
||||||
|
import { funnelOutline, caretBackCircleSharp } from 'ionicons/icons'
|
||||||
|
|
||||||
|
const serialItems = [
|
||||||
|
{
|
||||||
|
serial: 'APM001 INT',
|
||||||
|
production: '04-02-2026',
|
||||||
|
status: 'used',
|
||||||
|
location: 'Dusun Bambu',
|
||||||
|
installation: '03-04-2026',
|
||||||
|
history: '2x Maintenance'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
serial: 'APM002 INT',
|
||||||
|
production: '12-03-2026',
|
||||||
|
status: 'ready',
|
||||||
|
location: 'Standby WS',
|
||||||
|
installation: '09-02-2026',
|
||||||
|
history: '1x Maintenance'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
serial: 'APM003 INT',
|
||||||
|
production: '04-02-2026',
|
||||||
|
status: 'used',
|
||||||
|
location: 'Ancol',
|
||||||
|
installation: '03-04-2026',
|
||||||
|
history: '2x Maintenance'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
serial: 'APM004 INT',
|
||||||
|
production: '12-03-2026',
|
||||||
|
status: 'maintenance',
|
||||||
|
location: 'Park Zoo',
|
||||||
|
installation: '03-04-2026',
|
||||||
|
history: '1x Maintenance'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user