Done ui niise
This commit is contained in:
parent
45bd30b143
commit
772d425fdd
2
app.vue
2
app.vue
@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
useHead({
|
useHead({
|
||||||
title: "Niise | Innovative solutions for captivating content",
|
title: "Niise",
|
||||||
description: "Home page",
|
description: "Home page",
|
||||||
htmlAttrs: {
|
htmlAttrs: {
|
||||||
lang: "en",
|
lang: "en",
|
||||||
|
@ -105,42 +105,78 @@ export default [
|
|||||||
child: [],
|
child: [],
|
||||||
meta: {},
|
meta: {},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Tipografi",
|
||||||
|
path: "/tipografi",
|
||||||
|
icon: "ph:text-aa",
|
||||||
|
child: [],
|
||||||
|
meta: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Senarai Mesej",
|
||||||
|
path: "/senarai-mesej",
|
||||||
|
icon: "ic:outline-mail",
|
||||||
|
child: [],
|
||||||
|
meta: {},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
meta: {},
|
meta: {},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: "Administration",
|
header: "Prototaip Forensik",
|
||||||
description: "",
|
description: "",
|
||||||
child: [
|
child: [
|
||||||
{
|
{
|
||||||
title: "Configuration",
|
title: "FOR-01",
|
||||||
|
icon: "ph:number-circle-one-fill",
|
||||||
|
child: [
|
||||||
|
{
|
||||||
|
title: "Permohonan",
|
||||||
|
path: "/prototype/for-01/permohonan",
|
||||||
|
child: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Kemaskini Daftar",
|
||||||
|
path: "/prototype/for-01/kemaskini-daftar",
|
||||||
|
child: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: "Pengurusan",
|
||||||
|
description: "",
|
||||||
|
child: [
|
||||||
|
{
|
||||||
|
title: "Konfigurasi",
|
||||||
icon: "ic:outline-settings",
|
icon: "ic:outline-settings",
|
||||||
child: [
|
child: [
|
||||||
{
|
{
|
||||||
title: "Environment",
|
title: "Persekitaran",
|
||||||
path: "/devtool/config/environment",
|
path: "/devtool/config/environment",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Menu Editor",
|
title: "Penyelia Menu",
|
||||||
icon: "ci:menu-alt-03",
|
icon: "ci:menu-alt-03",
|
||||||
path: "/devtool/menu-editor",
|
path: "/devtool/menu-editor",
|
||||||
child: [],
|
child: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Manage Users",
|
title: "Penyelia Pengguna",
|
||||||
path: "/devtool/user-management",
|
path: "/devtool/user-management",
|
||||||
icon: "ph:user-circle-gear",
|
icon: "ph:user-circle-gear",
|
||||||
child: [
|
child: [
|
||||||
{
|
{
|
||||||
title: "User List",
|
title: "Pengguna",
|
||||||
path: "/devtool/user-management/user-list",
|
path: "/devtool/user-management/user-list",
|
||||||
icon: "",
|
icon: "",
|
||||||
child: [],
|
child: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Role List",
|
title: "Peranan",
|
||||||
path: "/devtool/user-management/role-list",
|
path: "/devtool/user-management/role-list",
|
||||||
icon: "",
|
icon: "",
|
||||||
child: [],
|
child: [],
|
||||||
@ -148,21 +184,21 @@ export default [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Content",
|
title: "Kandungan",
|
||||||
icon: "mdi:pencil-ruler",
|
icon: "mdi:pencil-ruler",
|
||||||
child: [
|
child: [
|
||||||
{
|
{
|
||||||
title: "Editor",
|
title: "Penyelia Kandungan",
|
||||||
path: "/devtool/content-editor",
|
path: "/devtool/content-editor",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Template",
|
title: "Templat",
|
||||||
path: "/devtool/content-editor/template",
|
path: "/devtool/content-editor/template",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "API Editor",
|
title: "Penyelia API",
|
||||||
path: "/devtool/api-editor",
|
path: "/devtool/api-editor",
|
||||||
icon: "material-symbols:api-rounded",
|
icon: "material-symbols:api-rounded",
|
||||||
child: [],
|
child: [],
|
||||||
|
@ -11,475 +11,328 @@ definePageMeta({
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const data1 = ref([]);
|
// Data baru untuk lapangan terbang teratas
|
||||||
const data2 = ref([]);
|
const topAirports = ref([
|
||||||
const data3 = ref([]);
|
|
||||||
const data4 = ref([]);
|
|
||||||
var sparkline1Data = [47, 45, 54, 38, 56, 24, 65];
|
|
||||||
var sparkline2Data = [61, 35, 66, 41, 59, 25, 32];
|
|
||||||
var sparkline3Data = [25, 18, 36, 41, 43, 35, 14];
|
|
||||||
var sparkline4Data = [8, 16, 22, 41, 43, 35, 14];
|
|
||||||
|
|
||||||
const changeKey = ref(0);
|
|
||||||
|
|
||||||
const customers = [
|
|
||||||
{
|
{
|
||||||
name: "Iqmal",
|
rank: 1,
|
||||||
age: "25",
|
name: "Lapangan Terbang Antarabangsa Kuala Lumpur (KLIA)",
|
||||||
city: "Kuala Lumpur",
|
visitors: 62000000,
|
||||||
country: "Malaysia",
|
|
||||||
totalPurchase: 1524,
|
|
||||||
purchase: 23,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Adi",
|
rank: 2,
|
||||||
age: "45",
|
name: "Lapangan Terbang Antarabangsa Kota Kinabalu",
|
||||||
city: "Pulau Pinang",
|
visitors: 9000000,
|
||||||
country: "Malaysia",
|
|
||||||
totalPurchase: 643,
|
|
||||||
purchase: 14,
|
|
||||||
},
|
},
|
||||||
|
{ rank: 3, name: "Lapangan Terbang Antarabangsa Penang", visitors: 8000000 },
|
||||||
|
{ rank: 4, name: "Lapangan Terbang Antarabangsa Kuching", visitors: 5500000 },
|
||||||
{
|
{
|
||||||
name: "Raziq",
|
rank: 5,
|
||||||
age: "21",
|
name: "Lapangan Terbang Antarabangsa Langkawi",
|
||||||
city: "Kelantan",
|
visitors: 3000000,
|
||||||
country: "Malaysia",
|
|
||||||
totalPurchase: 543,
|
|
||||||
purchase: 12,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Haqeem",
|
|
||||||
age: "19",
|
|
||||||
city: "Negeri Sembilan",
|
|
||||||
country: "Malaysia",
|
|
||||||
totalPurchase: 258,
|
|
||||||
purchase: 6,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const randomizeArray = function (arg) {
|
|
||||||
var array = arg.slice();
|
|
||||||
var currentIndex = array.length,
|
|
||||||
temporaryValue,
|
|
||||||
randomIndex;
|
|
||||||
|
|
||||||
while (0 !== currentIndex) {
|
|
||||||
randomIndex = Math.floor(Math.random() * currentIndex);
|
|
||||||
currentIndex -= 1;
|
|
||||||
|
|
||||||
temporaryValue = array[currentIndex];
|
|
||||||
array[currentIndex] = array[randomIndex];
|
|
||||||
array[randomIndex] = temporaryValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return array;
|
|
||||||
};
|
|
||||||
|
|
||||||
data1.value.push({
|
|
||||||
name: "Revenues",
|
|
||||||
data: randomizeArray(sparkline1Data),
|
|
||||||
});
|
|
||||||
|
|
||||||
data2.value.push({
|
|
||||||
name: "Users",
|
|
||||||
data: randomizeArray(sparkline2Data),
|
|
||||||
});
|
|
||||||
|
|
||||||
data3.value.push({
|
|
||||||
name: "Products",
|
|
||||||
data: randomizeArray(sparkline3Data),
|
|
||||||
});
|
|
||||||
|
|
||||||
data4.value.push({
|
|
||||||
name: "Viewers",
|
|
||||||
data: randomizeArray(sparkline4Data),
|
|
||||||
});
|
|
||||||
|
|
||||||
const chartOptions = computed(() => ({
|
|
||||||
chart: {
|
|
||||||
type: "area",
|
|
||||||
sparkline: {
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
stroke: {
|
|
||||||
curve: "smooth",
|
|
||||||
},
|
|
||||||
fill: {
|
|
||||||
opacity: 1,
|
|
||||||
},
|
|
||||||
labels: [...Array(7).keys()].map((n) => `2022-06-0${n + 1}`),
|
|
||||||
xaxis: {
|
|
||||||
type: "datetime",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Radial Chart
|
|
||||||
|
|
||||||
const radialData = ref([44, 55, 67, 83]);
|
|
||||||
|
|
||||||
const chartOptionsRadial = computed(() => ({
|
|
||||||
chart: {
|
|
||||||
height: 350,
|
|
||||||
type: "radialBar",
|
|
||||||
},
|
|
||||||
plotOptions: {
|
|
||||||
radialBar: {
|
|
||||||
dataLabels: {
|
|
||||||
style: {
|
|
||||||
colors: "#9CA3AF",
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
offsetY: 30,
|
|
||||||
fontSize: "18px",
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
offsetY: -15,
|
|
||||||
fontSize: "30px",
|
|
||||||
},
|
|
||||||
total: {
|
|
||||||
show: true,
|
|
||||||
label: "Total",
|
|
||||||
formatter: function (w) {
|
|
||||||
// By default this function returns the average of all series. The below is just an example to show the use of custom formatter function
|
|
||||||
return 249;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
labels: ["Product A", "Product B", "Product C", "Product D"],
|
|
||||||
stroke: {
|
|
||||||
lineCap: "round",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Transaction Graph
|
|
||||||
const transactionData = ref([
|
|
||||||
{
|
|
||||||
name: "Bill A",
|
|
||||||
data: [...Array(12).keys()].map((n) => Math.round(Math.random() * 100)),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Bill B",
|
|
||||||
data: [...Array(12).keys()].map((n) => Math.round(Math.random() * 100)),
|
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const chartOptionsTransaction = computed(() => ({
|
// Data baru untuk kad ringkasan pantas
|
||||||
chart: {
|
const quickSummary = ref([
|
||||||
height: 350,
|
{ title: "Jumlah Pelawat", value: "10.5 Juta", icon: "ic:outline-people" },
|
||||||
type: "area",
|
{
|
||||||
toolbar: {
|
title: "Pendapatan Pelancongan",
|
||||||
show: false,
|
value: "RM 86.14 Bilion",
|
||||||
},
|
icon: "ic:outline-attach-money",
|
||||||
},
|
},
|
||||||
dataLabels: {
|
{
|
||||||
enabled: false,
|
title: "Tempoh Penginapan Purata",
|
||||||
|
value: "6.1 Hari",
|
||||||
|
icon: "ic:outline-hotel",
|
||||||
},
|
},
|
||||||
stroke: {
|
{
|
||||||
curve: "smooth",
|
title: "Kepuasan Pelancong",
|
||||||
|
value: "92%",
|
||||||
|
icon: "ic:outline-sentiment-satisfied",
|
||||||
},
|
},
|
||||||
colors: ["#6366F1", "#F97316"],
|
]);
|
||||||
yaxis: {
|
|
||||||
labels: {
|
// Data Pelawat Malaysia
|
||||||
style: {
|
const visitorData = ref([
|
||||||
colors: "#9CA3AF",
|
{
|
||||||
fontSize: "12px",
|
name: "Pelawat Tempatan",
|
||||||
|
data: [5000000, 5500000, 6000000, 6500000, 7000000, 7500000],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Pelawat Asing",
|
||||||
|
data: [3000000, 3500000, 4000000, 4500000, 5000000, 5500000],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Data Pelawat Asing mengikut Negeri
|
||||||
|
const foreignVisitorsByState = ref([
|
||||||
|
{ state: "Selangor", visitors: 1500000 },
|
||||||
|
{ state: "Pulau Pinang", visitors: 1200000 },
|
||||||
|
{ state: "Johor", visitors: 1000000 },
|
||||||
|
{ state: "Sabah", visitors: 800000 },
|
||||||
|
{ state: "Sarawak", visitors: 600000 },
|
||||||
|
{ state: "Melaka", visitors: 500000 },
|
||||||
|
{ state: "Kedah", visitors: 400000 },
|
||||||
|
{ state: "Negeri Sembilan", visitors: 300000 },
|
||||||
|
{ state: "Perak", visitors: 250000 },
|
||||||
|
{ state: "Terengganu", visitors: 200000 },
|
||||||
|
{ state: "Kelantan", visitors: 150000 },
|
||||||
|
{ state: "Pahang", visitors: 100000 },
|
||||||
|
{ state: "Perlis", visitors: 50000 },
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Lapangan Terbang Keberangkatan Teratas
|
||||||
|
const departureData = ref([
|
||||||
|
{ airport: "JFK", departures: 1500 },
|
||||||
|
{ airport: "LHR", departures: 1200 },
|
||||||
|
{ airport: "CDG", departures: 1000 },
|
||||||
|
{ airport: "DXB", departures: 800 },
|
||||||
|
{ airport: "SIN", departures: 600 },
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Data Pelancong Berulang
|
||||||
|
const repeatVisitorsData = ref([
|
||||||
|
{ category: "1-2 kali", percentage: 45 },
|
||||||
|
{ category: "3-5 kali", percentage: 30 },
|
||||||
|
{ category: "6-10 kali", percentage: 15 },
|
||||||
|
{ category: ">10 kali", percentage: 10 },
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Data Negara Asal Pelancong Asing Teratas
|
||||||
|
const topVisitorCountries = ref([
|
||||||
|
{ country: "Singapura", visitors: 1500000 },
|
||||||
|
{ country: "Indonesia", visitors: 1200000 },
|
||||||
|
{ country: "China", visitors: 1000000 },
|
||||||
|
{ country: "Thailand", visitors: 800000 },
|
||||||
|
{ country: "India", visitors: 600000 },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const chartOptionsVisitors = computed(() => ({
|
||||||
|
chart: { height: 350, type: "line" },
|
||||||
|
stroke: { curve: "smooth", width: 2 },
|
||||||
|
xaxis: { categories: ["2018", "2019", "2020", "2021", "2022", "2023"] },
|
||||||
|
yaxis: { title: { text: "Bilangan Pelawat" } },
|
||||||
|
}));
|
||||||
|
|
||||||
|
const chartOptionsForeignVisitors = computed(() => ({
|
||||||
|
chart: { type: "bar" },
|
||||||
|
plotOptions: { bar: { horizontal: true } },
|
||||||
|
xaxis: { categories: foreignVisitorsByState.value.map((item) => item.state) },
|
||||||
|
}));
|
||||||
|
|
||||||
|
const chartOptionsDeparture = computed(() => ({
|
||||||
|
chart: { type: "bar" },
|
||||||
|
plotOptions: { bar: { horizontal: true } },
|
||||||
|
xaxis: { categories: departureData.value.map((item) => item.airport) },
|
||||||
|
}));
|
||||||
|
|
||||||
|
const chartOptionsRepeatVisitors = computed(() => ({
|
||||||
|
chart: { type: "pie" },
|
||||||
|
labels: repeatVisitorsData.value.map((item) => item.category),
|
||||||
|
responsive: [
|
||||||
|
{
|
||||||
|
breakpoint: 480,
|
||||||
|
options: {
|
||||||
|
chart: {
|
||||||
|
width: 200,
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
position: "bottom",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
|
||||||
|
const chartOptionsTopCountries = computed(() => ({
|
||||||
|
chart: { type: "bar" },
|
||||||
|
plotOptions: {
|
||||||
|
bar: { horizontal: false, columnWidth: "55%", endingShape: "rounded" },
|
||||||
},
|
},
|
||||||
xaxis: {
|
dataLabels: { enabled: false },
|
||||||
type: "datetime",
|
stroke: { show: true, width: 2, colors: ["transparent"] },
|
||||||
categories: [
|
xaxis: { categories: topVisitorCountries.value.map((item) => item.country) },
|
||||||
"2022-01-01",
|
yaxis: { title: { text: "Bilangan Pelawat" } },
|
||||||
"2022-02-01",
|
fill: { opacity: 1 },
|
||||||
"2022-03-01",
|
|
||||||
"2022-04-01",
|
|
||||||
"2022-05-01",
|
|
||||||
"2022-06-01",
|
|
||||||
"2022-07-01",
|
|
||||||
"2022-08-01",
|
|
||||||
"2022-09-01",
|
|
||||||
"2022-10-01",
|
|
||||||
"2022-11-01",
|
|
||||||
"2022-12-01",
|
|
||||||
],
|
|
||||||
labels: {
|
|
||||||
style: {
|
|
||||||
colors: "#9CA3AF",
|
|
||||||
fontSize: "14px",
|
|
||||||
fontWeight: 400,
|
|
||||||
},
|
|
||||||
datetimeFormatter: {
|
|
||||||
month: "MMM",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
position: "top",
|
|
||||||
horizontalAlign: "left",
|
|
||||||
labels: {
|
|
||||||
colors: "#9CA3AF",
|
|
||||||
useSeriesColors: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tooltip: {
|
tooltip: {
|
||||||
x: {
|
y: {
|
||||||
format: "MMMM",
|
formatter: function (val) {
|
||||||
|
return val.toLocaleString() + " pelawat";
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setTimeout(() => {
|
// Sebarang logik yang diperlukan semasa pemasangan
|
||||||
changeKey.value++;
|
|
||||||
}, 500);
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<LayoutsBreadcrumb />
|
<LayoutsBreadcrumb />
|
||||||
<!-- First Row -->
|
<!-- Kad Ringkasan Pantas -->
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-4 gap-x-6">
|
<div class="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-4 gap-6">
|
||||||
<!-- Summary Card #1 -->
|
<rs-card
|
||||||
<rs-card>
|
v-for="(item, index) in quickSummary"
|
||||||
<div class="summary-1 pt-5 pb-3 px-5 flex items-center gap-4">
|
:key="index"
|
||||||
|
class="transition-all duration-300 hover:shadow-lg"
|
||||||
|
>
|
||||||
|
<div class="pt-5 pb-3 px-5 flex items-center gap-4">
|
||||||
<div
|
<div
|
||||||
class="p-5 flex justify-center items-center bg-primary/20 rounded-2xl"
|
class="p-5 flex justify-center items-center bg-primary/20 rounded-2xl transition-all duration-300 hover:bg-primary/30"
|
||||||
>
|
>
|
||||||
<Icon class="text-primary" name="ic:outline-attach-money"></Icon>
|
<Icon class="text-primary text-3xl" :name="item.icon"></Icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1 truncate">
|
<div class="flex-1 truncate">
|
||||||
<span class="block font-semibold text-xl leading-tight">
|
<span class="block font-bold text-2xl leading-tight text-primary">
|
||||||
RM 100,000</span
|
{{ item.value }}
|
||||||
>
|
</span>
|
||||||
<span class="text-base font-semibold text-gray-500"
|
<span class="text-sm font-medium text-gray-600">
|
||||||
>Total Revenues</span
|
{{ item.title }}
|
||||||
>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<client-only>
|
|
||||||
<VueApexCharts
|
|
||||||
:key="changeKey"
|
|
||||||
width="100%"
|
|
||||||
height="53"
|
|
||||||
:options="{
|
|
||||||
...chartOptions,
|
|
||||||
colors: ['#F43F5E'],
|
|
||||||
yaxis: {
|
|
||||||
min: 0,
|
|
||||||
max: Math.max(...data1[0].data) + 10,
|
|
||||||
},
|
|
||||||
}"
|
|
||||||
:series="data1"
|
|
||||||
></VueApexCharts>
|
|
||||||
</client-only>
|
|
||||||
</rs-card>
|
|
||||||
<!-- Summary Card #2 -->
|
|
||||||
<rs-card>
|
|
||||||
<div class="summary-2 pt-5 pb-3 px-5 flex items-center gap-4">
|
|
||||||
<div
|
|
||||||
class="p-5 flex justify-center items-center bg-indigo-100 rounded-2xl"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
class="text-indigo-500"
|
|
||||||
name="ic:outline-account-circle"
|
|
||||||
></Icon>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1 truncate">
|
|
||||||
<span class="block font-semibold text-xl leading-tight"> 512</span>
|
|
||||||
<span class="text-base font-semibold text-gray-500"
|
|
||||||
>Total Users</span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<client-only>
|
|
||||||
<VueApexCharts
|
|
||||||
:key="changeKey"
|
|
||||||
width="100%"
|
|
||||||
height="53"
|
|
||||||
:options="{
|
|
||||||
...chartOptions,
|
|
||||||
colors: ['#6366F1'],
|
|
||||||
yaxis: {
|
|
||||||
min: 0,
|
|
||||||
max: Math.max(...data2[0].data) + 10,
|
|
||||||
},
|
|
||||||
}"
|
|
||||||
:series="data2"
|
|
||||||
></VueApexCharts>
|
|
||||||
</client-only>
|
|
||||||
</rs-card>
|
|
||||||
<!-- Summary Card #3 -->
|
|
||||||
<rs-card>
|
|
||||||
<div class="summary-3 pt-5 pb-3 px-5 flex items-center gap-4">
|
|
||||||
<div
|
|
||||||
class="p-5 flex justify-center items-center bg-orange-100 rounded-2xl"
|
|
||||||
>
|
|
||||||
<Icon class="text-orange-500" name="ic:outline-shopping-bag"></Icon>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1 truncate">
|
|
||||||
<span class="block font-semibold text-xl leading-tight"> 20</span>
|
|
||||||
<span class="text-base font-semibold text-gray-500"
|
|
||||||
>Total Products</span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<client-only>
|
|
||||||
<VueApexCharts
|
|
||||||
:key="changeKey"
|
|
||||||
width="100%"
|
|
||||||
height="53"
|
|
||||||
:options="{
|
|
||||||
...chartOptions,
|
|
||||||
colors: ['#F97316'],
|
|
||||||
yaxis: {
|
|
||||||
min: 0,
|
|
||||||
max: Math.max(...data3[0].data) + 10,
|
|
||||||
},
|
|
||||||
}"
|
|
||||||
:series="data3"
|
|
||||||
></VueApexCharts>
|
|
||||||
</client-only>
|
|
||||||
</rs-card>
|
|
||||||
<!-- Summary Card #4 -->
|
|
||||||
<rs-card>
|
|
||||||
<div class="summary-4 pt-5 pb-3 px-5 flex items-center gap-4">
|
|
||||||
<div
|
|
||||||
class="p-5 flex justify-center items-center bg-blue-100 rounded-2xl"
|
|
||||||
>
|
|
||||||
<Icon class="text-blue-500" name="ic:outline-remove-red-eye"></Icon>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1 truncate">
|
|
||||||
<span class="block font-semibold text-xl leading-tight">
|
|
||||||
2,452</span
|
|
||||||
>
|
|
||||||
<span class="text-base font-semibold text-gray-500"
|
|
||||||
>Total Viewers</span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<client-only>
|
|
||||||
<VueApexCharts
|
|
||||||
:key="changeKey"
|
|
||||||
width="100%"
|
|
||||||
height="53"
|
|
||||||
:options="{
|
|
||||||
...chartOptions,
|
|
||||||
colors: ['#3B82F6'],
|
|
||||||
yaxis: {
|
|
||||||
min: 0,
|
|
||||||
max: Math.max(...data4[0].data) + 10,
|
|
||||||
},
|
|
||||||
}"
|
|
||||||
:series="data4"
|
|
||||||
></VueApexCharts>
|
|
||||||
</client-only>
|
|
||||||
</rs-card>
|
</rs-card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col md:flex-row gap-x-6">
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
||||||
<div class="w-12/2 md:w-8/12 flex flex-col">
|
<!-- Gambaran Keseluruhan Pelawat Malaysia -->
|
||||||
<!-- Graph -->
|
<rs-card class="col-span-1 lg:col-span-2">
|
||||||
<rs-card class="flex-1">
|
<template #header>
|
||||||
<template #header> Transaction </template>
|
<h2 class="text-xl font-bold text-primary">
|
||||||
<template #body>
|
Gambaran Keseluruhan Pelawat
|
||||||
<client-only>
|
</h2>
|
||||||
<VueApexCharts
|
</template>
|
||||||
:key="changeKey"
|
<template #body>
|
||||||
width="100%"
|
<client-only>
|
||||||
height="300"
|
<VueApexCharts
|
||||||
name="area"
|
width="100%"
|
||||||
:options="chartOptionsTransaction"
|
height="350"
|
||||||
:series="transactionData"
|
type="line"
|
||||||
></VueApexCharts
|
:options="chartOptionsVisitors"
|
||||||
></client-only>
|
:series="visitorData"
|
||||||
</template>
|
></VueApexCharts>
|
||||||
</rs-card>
|
</client-only>
|
||||||
<rs-card class="flex-1">
|
</template>
|
||||||
<template #header> Referral</template>
|
</rs-card>
|
||||||
<template #body>
|
|
||||||
<div
|
<!-- Pelawat Asing mengikut Negeri -->
|
||||||
v-for="(val, index) in customers"
|
<rs-card>
|
||||||
:key="index"
|
<template #header>
|
||||||
class="flex justify-between items-center rounded-lg bg-[rgb(var(--bg-1))] p-5 first:mt-0 mt-3"
|
<h2 class="text-lg font-semibold text-primary">
|
||||||
>
|
Pelawat Asing mengikut Negeri
|
||||||
<div class="flex items-center gap-x-4">
|
</h2>
|
||||||
<img
|
</template>
|
||||||
src="@/assets/img/avatar/user.webp"
|
<template #body>
|
||||||
class="h-10 w-10 rounded-lg"
|
<client-only>
|
||||||
/>
|
<VueApexCharts
|
||||||
<div class="flex-1">
|
width="100%"
|
||||||
<div class="flex flex-col">
|
height="300"
|
||||||
<span
|
type="bar"
|
||||||
class="text-gray-900 dark:text-white font-semibold text-lg"
|
:options="chartOptionsForeignVisitors"
|
||||||
>
|
:series="[
|
||||||
{{ val.name }}
|
{ data: foreignVisitorsByState.map((item) => item.visitors) },
|
||||||
</span>
|
]"
|
||||||
<span class="text-gray-600 dark:text-gray-50 text-sm">
|
></VueApexCharts>
|
||||||
RM{{ parseFloat(val.totalPurchase).toFixed(2) }} |
|
</client-only>
|
||||||
{{ val.purchase }} sold
|
</template>
|
||||||
</span>
|
</rs-card>
|
||||||
</div>
|
|
||||||
</div>
|
<!-- Pelancong Berulang -->
|
||||||
</div>
|
<rs-card>
|
||||||
<div>
|
<template #header>
|
||||||
<button
|
<h2 class="text-lg font-semibold text-primary">
|
||||||
class="flex items-center p-4 rounded-full bg-[rgb(var(--bg-2))] hover:bg-[rgb(var(--bg-2))]/10 shadow-md"
|
Kekerapan Lawatan Pelancong
|
||||||
>
|
</h2>
|
||||||
<Icon size="20px" name="ic:baseline-mail-outline"></Icon>
|
</template>
|
||||||
</button>
|
<template #body>
|
||||||
</div>
|
<client-only>
|
||||||
</div>
|
<VueApexCharts
|
||||||
</template>
|
width="100%"
|
||||||
</rs-card>
|
height="300"
|
||||||
</div>
|
type="pie"
|
||||||
<div class="w-12/2 md:w-4/12 flex flex-col">
|
:options="chartOptionsRepeatVisitors"
|
||||||
<!-- Monthly Target Radial -->
|
:series="repeatVisitorsData.map((item) => item.percentage)"
|
||||||
<rs-card class="flex-1">
|
></VueApexCharts>
|
||||||
<template #header> Monthly Target </template>
|
</client-only>
|
||||||
<template #body>
|
</template>
|
||||||
<client-only>
|
</rs-card>
|
||||||
<VueApexCharts
|
|
||||||
:key="changeKey"
|
|
||||||
width="100%"
|
|
||||||
height="300"
|
|
||||||
name="radialBar"
|
|
||||||
:options="chartOptionsRadial"
|
|
||||||
:series="radialData"
|
|
||||||
></VueApexCharts>
|
|
||||||
</client-only>
|
|
||||||
<hr class="my-4" />
|
|
||||||
<p class="text-xl py-5 font-medium">Products</p>
|
|
||||||
<div
|
|
||||||
class="flex item-center gap-x-4"
|
|
||||||
:class="{
|
|
||||||
'mt-0': index === 0,
|
|
||||||
'mt-3': index !== 0,
|
|
||||||
}"
|
|
||||||
v-for="(val, index) in ['A', 'B', 'C', 'D', 'E']"
|
|
||||||
:key="index"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src="@/assets/img/default-thumbnail.jpg"
|
|
||||||
class="h-20 w-20 object-cover rounded-lg"
|
|
||||||
/>
|
|
||||||
<div class="flex-1 flex items-center">
|
|
||||||
<div>
|
|
||||||
<span class="font-semibold text-lg leading-tight"
|
|
||||||
>Product {{ val }}</span
|
|
||||||
>
|
|
||||||
<p>
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</rs-card>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Negara Asal Pelancong Asing Teratas -->
|
||||||
|
<rs-card class="mb-6">
|
||||||
|
<template #header>
|
||||||
|
<h2 class="text-xl font-bold text-primary">
|
||||||
|
Negara Asal Pelancong Asing Teratas
|
||||||
|
</h2>
|
||||||
|
</template>
|
||||||
|
<template #body>
|
||||||
|
<client-only>
|
||||||
|
<VueApexCharts
|
||||||
|
width="100%"
|
||||||
|
height="350"
|
||||||
|
type="bar"
|
||||||
|
:options="chartOptionsTopCountries"
|
||||||
|
:series="[
|
||||||
|
{
|
||||||
|
name: 'Pelawat',
|
||||||
|
data: topVisitorCountries.map((item) => item.visitors),
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
></VueApexCharts>
|
||||||
|
</client-only>
|
||||||
|
</template>
|
||||||
|
</rs-card>
|
||||||
|
|
||||||
|
<rs-card class="mb-6">
|
||||||
|
<template #header>
|
||||||
|
<h2 class="text-xl font-bold text-primary">
|
||||||
|
Lapangan Terbang Teratas dengan Pelawat Terbanyak
|
||||||
|
</h2>
|
||||||
|
</template>
|
||||||
|
<template #body>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="min-w-full divide-y divide-gray-200">
|
||||||
|
<thead class="bg-gray-50">
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||||
|
>
|
||||||
|
Kedudukan
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||||
|
>
|
||||||
|
Nama Lapangan Terbang
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||||
|
>
|
||||||
|
Jumlah Pelawat
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="bg-white divide-y divide-gray-200">
|
||||||
|
<tr
|
||||||
|
v-for="airport in topAirports"
|
||||||
|
:key="airport.rank"
|
||||||
|
class="hover:bg-gray-50 transition-colors duration-200"
|
||||||
|
>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap font-medium">
|
||||||
|
{{ airport.rank }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap">{{ airport.name }}</td>
|
||||||
|
<td
|
||||||
|
class="px-6 py-4 whitespace-nowrap font-semibold text-primary"
|
||||||
|
>
|
||||||
|
{{ airport.visitors.toLocaleString() }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</rs-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
import { useThemeStore } from "~/stores/theme";
|
import { useThemeStore } from "~/stores/theme";
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
title: "API Code Editor",
|
title: "Penyunting Kod API",
|
||||||
middleware: ["auth"],
|
middleware: ["auth"],
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
});
|
});
|
||||||
@ -63,8 +63,8 @@ if (data.value.statusCode === 200) {
|
|||||||
} else {
|
} else {
|
||||||
$swal
|
$swal
|
||||||
.fire({
|
.fire({
|
||||||
title: "Error",
|
title: "Ralat",
|
||||||
text: "The API you are trying to edit is not found. Please choose a API to edit.",
|
text: "API yang anda cuba sunting tidak dijumpai. Sila pilih API untuk disunting.",
|
||||||
icon: "error",
|
icon: "error",
|
||||||
confirmButtonText: "Ok",
|
confirmButtonText: "Ok",
|
||||||
})
|
})
|
||||||
@ -134,8 +134,8 @@ const saveCode = async () => {
|
|||||||
|
|
||||||
if (linterError.value) {
|
if (linterError.value) {
|
||||||
$swal.fire({
|
$swal.fire({
|
||||||
title: "Error",
|
title: "Ralat",
|
||||||
text: "There is an error in your code. Please fix it before saving.",
|
text: "Terdapat ralat dalam kod anda. Sila betulkannya sebelum menyimpan.",
|
||||||
icon: "error",
|
icon: "error",
|
||||||
confirmButtonText: "Ok",
|
confirmButtonText: "Ok",
|
||||||
});
|
});
|
||||||
@ -153,8 +153,8 @@ const saveCode = async () => {
|
|||||||
});
|
});
|
||||||
if (data.value.statusCode === 200) {
|
if (data.value.statusCode === 200) {
|
||||||
$swal.fire({
|
$swal.fire({
|
||||||
title: "Success",
|
title: "Berjaya",
|
||||||
text: "The code has been saved successfully.",
|
text: "Kod telah berjaya disimpan.",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
confirmButtonText: "Ok",
|
confirmButtonText: "Ok",
|
||||||
timer: 1000,
|
timer: 1000,
|
||||||
@ -175,11 +175,11 @@ const saveCode = async () => {
|
|||||||
}}</rs-alert>
|
}}</rs-alert>
|
||||||
<rs-card>
|
<rs-card>
|
||||||
<rs-tab fill>
|
<rs-tab fill>
|
||||||
<rs-tab-item title="Editor">
|
<rs-tab-item title="Penyunting">
|
||||||
<div class="flex justify-end gap-2 mb-4">
|
<div class="flex justify-end gap-2 mb-4">
|
||||||
<rs-button class="!p-2" @click="formatCode">
|
<rs-button class="!p-2" @click="formatCode">
|
||||||
<Icon name="simple-icons:prettier" size="20px" class="mr-1" />
|
<Icon name="simple-icons:prettier" size="20px" class="mr-1" />
|
||||||
Format Code</rs-button
|
Format Kod</rs-button
|
||||||
>
|
>
|
||||||
<rs-button class="!p-2" @click="saveCode">
|
<rs-button class="!p-2" @click="saveCode">
|
||||||
<Icon
|
<Icon
|
||||||
@ -187,7 +187,7 @@ const saveCode = async () => {
|
|||||||
size="20px"
|
size="20px"
|
||||||
class="mr-1"
|
class="mr-1"
|
||||||
/>
|
/>
|
||||||
Save API
|
Simpan API
|
||||||
</rs-button>
|
</rs-button>
|
||||||
</div>
|
</div>
|
||||||
<Transition>
|
<Transition>
|
||||||
@ -198,12 +198,12 @@ const saveCode = async () => {
|
|||||||
size="20px"
|
size="20px"
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<div class="font-bold">ESLint Error</div>
|
<div class="font-bold">Ralat ESLint</div>
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
{{ linterErrorText }}
|
{{ linterErrorText }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs mt-2">
|
<div class="text-xs mt-2">
|
||||||
Line: {{ linterErrorLine }} Column: {{ linterErrorColumn }}
|
Baris: {{ linterErrorLine }} Lajur: {{ linterErrorColumn }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -216,7 +216,7 @@ const saveCode = async () => {
|
|||||||
mode="javascript"
|
mode="javascript"
|
||||||
/>
|
/>
|
||||||
</rs-tab-item>
|
</rs-tab-item>
|
||||||
<rs-tab-item title="API Tester">
|
<rs-tab-item title="Penguji API">
|
||||||
<rs-api-tester :url="route.query?.path" />
|
<rs-api-tester :url="route.query?.path" />
|
||||||
</rs-tab-item>
|
</rs-tab-item>
|
||||||
</rs-tab>
|
</rs-tab>
|
||||||
|
@ -78,8 +78,8 @@ const saveAddAPI = async () => {
|
|||||||
|
|
||||||
if (data.value.statusCode === 200) {
|
if (data.value.statusCode === 200) {
|
||||||
nuxtApp.$swal.fire({
|
nuxtApp.$swal.fire({
|
||||||
title: "Success",
|
title: "Berjaya",
|
||||||
text: "The code has been saved successfully.",
|
text: "Kod telah berjaya disimpan.",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
confirmButtonText: "Ok",
|
confirmButtonText: "Ok",
|
||||||
timer: 1000,
|
timer: 1000,
|
||||||
@ -105,8 +105,8 @@ const saveEditAPI = async () => {
|
|||||||
|
|
||||||
if (data.value.statusCode === 200) {
|
if (data.value.statusCode === 200) {
|
||||||
nuxtApp.$swal.fire({
|
nuxtApp.$swal.fire({
|
||||||
title: "Success",
|
title: "Berjaya",
|
||||||
text: "The code has been saved successfully.",
|
text: "Kod telah berjaya disimpan.",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
confirmButtonText: "Ok",
|
confirmButtonText: "Ok",
|
||||||
timer: 1000,
|
timer: 1000,
|
||||||
@ -122,13 +122,14 @@ const saveEditAPI = async () => {
|
|||||||
const deleteAPI = async (apiURL) => {
|
const deleteAPI = async (apiURL) => {
|
||||||
nuxtApp.$swal
|
nuxtApp.$swal
|
||||||
.fire({
|
.fire({
|
||||||
title: "Are you sure to delete this API?",
|
title: "Adakah anda pasti untuk memadam API ini?",
|
||||||
text: "You won't be able to revert this!",
|
text: "Anda tidak akan dapat memulihkan ini!",
|
||||||
icon: "warning",
|
icon: "warning",
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
confirmButtonColor: "#3085d6",
|
confirmButtonColor: "#3085d6",
|
||||||
cancelButtonColor: "#d33",
|
cancelButtonColor: "#d33",
|
||||||
confirmButtonText: "Yes, delete it!",
|
confirmButtonText: "Ya, padamkan!",
|
||||||
|
cancelButtonText: "Batal",
|
||||||
})
|
})
|
||||||
.then(async (result) => {
|
.then(async (result) => {
|
||||||
if (result.isConfirmed) {
|
if (result.isConfirmed) {
|
||||||
@ -143,8 +144,8 @@ const deleteAPI = async (apiURL) => {
|
|||||||
|
|
||||||
if (data.value.statusCode === 200) {
|
if (data.value.statusCode === 200) {
|
||||||
nuxtApp.$swal.fire({
|
nuxtApp.$swal.fire({
|
||||||
title: "Success",
|
title: "Berjaya",
|
||||||
text: "The code has been saved successfully.",
|
text: "Kod telah berjaya disimpan.",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
confirmButtonText: "Ok",
|
confirmButtonText: "Ok",
|
||||||
timer: 1000,
|
timer: 1000,
|
||||||
@ -164,13 +165,13 @@ const deleteAPI = async (apiURL) => {
|
|||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<Icon class="mr-2 flex justify-center" name="ic:outline-info"></Icon
|
<Icon class="mr-2 flex justify-center" name="ic:outline-info"></Icon
|
||||||
>Info
|
>Maklumat
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #body>
|
<template #body>
|
||||||
<p class="mb-4">
|
<p class="mb-4">
|
||||||
This page is used to edit the api for the server side. You can edit
|
Halaman ini digunakan untuk mengedit API untuk bahagian pelayan. Anda boleh mengedit
|
||||||
the api by choosing the api to edit from the card list below.
|
API dengan memilih API untuk diedit dari senarai kad di bawah.
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</rs-card>
|
</rs-card>
|
||||||
@ -180,14 +181,14 @@ const deleteAPI = async (apiURL) => {
|
|||||||
<div class="flex justify-end items-center mb-4">
|
<div class="flex justify-end items-center mb-4">
|
||||||
<rs-button @click="openModalAdd">
|
<rs-button @click="openModalAdd">
|
||||||
<Icon name="material-symbols:add" class="mr-1"></Icon>
|
<Icon name="material-symbols:add" class="mr-1"></Icon>
|
||||||
Add API
|
Tambah API
|
||||||
</rs-button>
|
</rs-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Search Button -->
|
<!-- Search Button -->
|
||||||
<FormKit
|
<FormKit
|
||||||
v-model="searchText"
|
v-model="searchText"
|
||||||
placeholder="Search Title..."
|
placeholder="Cari Tajuk..."
|
||||||
type="search"
|
type="search"
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
/>
|
/>
|
||||||
@ -214,7 +215,7 @@ const deleteAPI = async (apiURL) => {
|
|||||||
name="material-symbols:code-blocks-outline-rounded"
|
name="material-symbols:code-blocks-outline-rounded"
|
||||||
class="mr-2"
|
class="mr-2"
|
||||||
/>
|
/>
|
||||||
Code Editor
|
Editor Kod
|
||||||
</rs-button>
|
</rs-button>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<rs-button @click="openModalEdit(api.url)">
|
<rs-button @click="openModalEdit(api.url)">
|
||||||
@ -233,9 +234,9 @@ const deleteAPI = async (apiURL) => {
|
|||||||
</rs-card>
|
</rs-card>
|
||||||
|
|
||||||
<rs-modal
|
<rs-modal
|
||||||
title="Add API"
|
title="Tambah API"
|
||||||
v-model="showModalAdd"
|
v-model="showModalAdd"
|
||||||
ok-title="Save"
|
ok-title="Simpan"
|
||||||
:ok-callback="saveAddAPI"
|
:ok-callback="saveAddAPI"
|
||||||
>
|
>
|
||||||
<FormKit type="text" label="Url" v-model="showModalAddForm.apiURL">
|
<FormKit type="text" label="Url" v-model="showModalAddForm.apiURL">
|
||||||
@ -248,9 +249,9 @@ const deleteAPI = async (apiURL) => {
|
|||||||
</rs-modal>
|
</rs-modal>
|
||||||
|
|
||||||
<rs-modal
|
<rs-modal
|
||||||
title="Add API"
|
title="Edit API"
|
||||||
v-model="showModalEdit"
|
v-model="showModalEdit"
|
||||||
ok-title="Save"
|
ok-title="Simpan"
|
||||||
:ok-callback="saveEditAPI"
|
:ok-callback="saveEditAPI"
|
||||||
>
|
>
|
||||||
<FormKit type="text" label="Url" v-model="showModalEditForm.apiURL">
|
<FormKit type="text" label="Url" v-model="showModalEditForm.apiURL">
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
title: "Code Editor",
|
title: "Penyunting Kod",
|
||||||
middleware: ["auth"],
|
middleware: ["auth"],
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
});
|
});
|
||||||
@ -28,8 +28,8 @@ const page = router.getRoutes().find((page) => {
|
|||||||
if (!route.query.page || !page) {
|
if (!route.query.page || !page) {
|
||||||
$swal
|
$swal
|
||||||
.fire({
|
.fire({
|
||||||
title: "Error",
|
title: "Ralat",
|
||||||
text: "The page you are trying to edit is not found. Please choose a page to edit.",
|
text: "Halaman yang anda cuba sunting tidak dijumpai. Sila pilih halaman untuk disunting.",
|
||||||
icon: "error",
|
icon: "error",
|
||||||
confirmButtonText: "Ok",
|
confirmButtonText: "Ok",
|
||||||
})
|
})
|
||||||
@ -62,8 +62,8 @@ if (data.value.statusCode === 200) {
|
|||||||
if (data.value?.mode == "index") page.path = page.path + "/index";
|
if (data.value?.mode == "index") page.path = page.path + "/index";
|
||||||
} else {
|
} else {
|
||||||
$swal.fire({
|
$swal.fire({
|
||||||
title: "Error",
|
title: "Ralat",
|
||||||
text: "The page you are trying to edit is not found. Please choose a page to edit. You will be redirected to the content editor page.",
|
text: "Halaman yang anda cuba sunting tidak dijumpai. Sila pilih halaman untuk disunting. Anda akan dialihkan ke halaman penyunting kandungan.",
|
||||||
icon: "error",
|
icon: "error",
|
||||||
confirmButtonText: "Ok",
|
confirmButtonText: "Ok",
|
||||||
timer: 3000,
|
timer: 3000,
|
||||||
@ -132,8 +132,8 @@ const saveCode = async () => {
|
|||||||
|
|
||||||
if (linterError.value) {
|
if (linterError.value) {
|
||||||
$swal.fire({
|
$swal.fire({
|
||||||
title: "Error",
|
title: "Ralat",
|
||||||
text: "There is an error in your code. Please fix it before saving.",
|
text: "Terdapat ralat dalam kod anda. Sila betulkannya sebelum menyimpan.",
|
||||||
icon: "error",
|
icon: "error",
|
||||||
confirmButtonText: "Ok",
|
confirmButtonText: "Ok",
|
||||||
});
|
});
|
||||||
@ -150,8 +150,8 @@ const saveCode = async () => {
|
|||||||
});
|
});
|
||||||
if (data.value.statusCode === 200) {
|
if (data.value.statusCode === 200) {
|
||||||
$swal.fire({
|
$swal.fire({
|
||||||
title: "Success",
|
title: "Berjaya",
|
||||||
text: "The code has been saved successfully.",
|
text: "Kod telah berjaya disimpan.",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
confirmButtonText: "Ok",
|
confirmButtonText: "Ok",
|
||||||
timer: 1000,
|
timer: 1000,
|
||||||
@ -175,7 +175,7 @@ const saveCode = async () => {
|
|||||||
<div class="flex justify-end gap-2 mb-4">
|
<div class="flex justify-end gap-2 mb-4">
|
||||||
<rs-button class="!p-2" @click="formatCode">
|
<rs-button class="!p-2" @click="formatCode">
|
||||||
<Icon name="simple-icons:prettier" size="20px" class="mr-1" />
|
<Icon name="simple-icons:prettier" size="20px" class="mr-1" />
|
||||||
Format Code</rs-button
|
Format Kod</rs-button
|
||||||
>
|
>
|
||||||
<rs-button class="!p-2" @click="saveCode">
|
<rs-button class="!p-2" @click="saveCode">
|
||||||
<Icon
|
<Icon
|
||||||
@ -183,7 +183,7 @@ const saveCode = async () => {
|
|||||||
size="20px"
|
size="20px"
|
||||||
class="mr-1"
|
class="mr-1"
|
||||||
/>
|
/>
|
||||||
Save Code
|
Simpan Kod
|
||||||
</rs-button>
|
</rs-button>
|
||||||
</div>
|
</div>
|
||||||
<Transition>
|
<Transition>
|
||||||
@ -191,12 +191,12 @@ const saveCode = async () => {
|
|||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<Icon name="material-symbols:error-outline-rounded" size="20px" />
|
<Icon name="material-symbols:error-outline-rounded" size="20px" />
|
||||||
<div>
|
<div>
|
||||||
<div class="font-bold">ESLint Error</div>
|
<div class="font-bold">Ralat ESLint</div>
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
{{ linterErrorText }}
|
{{ linterErrorText }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs mt-2">
|
<div class="text-xs mt-2">
|
||||||
Line: {{ linterErrorLine }} Column: {{ linterErrorColumn }}
|
Baris: {{ linterErrorLine }} Lajur: {{ linterErrorColumn }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
title: "Content Editor",
|
title: "Penyunting Kandungan",
|
||||||
middleware: ["auth"],
|
middleware: ["auth"],
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
});
|
});
|
||||||
@ -15,7 +15,7 @@ const pages = getPages.filter((page) => {
|
|||||||
return (
|
return (
|
||||||
page.path.includes("/devtool") === false &&
|
page.path.includes("/devtool") === false &&
|
||||||
page.meta?.title &&
|
page.meta?.title &&
|
||||||
page.meta?.title !== "Home" &&
|
page.meta?.title !== "Laman Utama" &&
|
||||||
page.name
|
page.name
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -44,7 +44,7 @@ const capitalizeSentence = (sentence) => {
|
|||||||
.join(" ");
|
.join(" ");
|
||||||
};
|
};
|
||||||
|
|
||||||
const templateOptions = ref([{ label: "Select Template", value: "" }]);
|
const templateOptions = ref([{ label: "Pilih Templat", value: "" }]);
|
||||||
const selectTemplate = ref("");
|
const selectTemplate = ref("");
|
||||||
|
|
||||||
const { data: templates } = await useFetch(
|
const { data: templates } = await useFetch(
|
||||||
@ -74,13 +74,13 @@ const importTemplate = (pageName) => {
|
|||||||
const confirmModal = async () => {
|
const confirmModal = async () => {
|
||||||
$swal
|
$swal
|
||||||
.fire({
|
.fire({
|
||||||
title: "Are you sure you want to import this template?",
|
title: "Adakah anda pasti mahu mengimport templat ini?",
|
||||||
text: "This action cannot be undone.",
|
text: "Tindakan ini tidak boleh dibatalkan.",
|
||||||
icon: "warning",
|
icon: "warning",
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
confirmButtonColor: "#3085d6",
|
confirmButtonColor: "#3085d6",
|
||||||
cancelButtonColor: "#d33",
|
cancelButtonColor: "#d33",
|
||||||
confirmButtonText: "Yes",
|
confirmButtonText: "Ya",
|
||||||
})
|
})
|
||||||
.then(async (result) => {
|
.then(async (result) => {
|
||||||
if (result.isConfirmed) {
|
if (result.isConfirmed) {
|
||||||
@ -98,7 +98,7 @@ const confirmModal = async () => {
|
|||||||
|
|
||||||
if (res.value.statusCode == 200) {
|
if (res.value.statusCode == 200) {
|
||||||
$swal.fire({
|
$swal.fire({
|
||||||
title: "Success",
|
title: "Berjaya",
|
||||||
text: res.value.message,
|
text: res.value.message,
|
||||||
icon: "success",
|
icon: "success",
|
||||||
confirmButtonText: "Ok",
|
confirmButtonText: "Ok",
|
||||||
@ -123,14 +123,14 @@ const confirmModal = async () => {
|
|||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<Icon class="mr-2 flex justify-center" name="ic:outline-info"></Icon
|
<Icon class="mr-2 flex justify-center" name="ic:outline-info"></Icon
|
||||||
>Info
|
>Maklumat
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #body>
|
<template #body>
|
||||||
<p class="mb-4">
|
<p class="mb-4">
|
||||||
This page is used to edit the content of a page. You can edit the
|
Halaman ini digunakan untuk menyunting kandungan halaman. Anda boleh menyunting
|
||||||
content of the page by choosing the page to edit from the card list
|
kandungan halaman dengan memilih halaman untuk disunting dari senarai kad
|
||||||
below.
|
di bawah.
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</rs-card>
|
</rs-card>
|
||||||
@ -140,7 +140,7 @@ const confirmModal = async () => {
|
|||||||
<!-- Search Button -->
|
<!-- Search Button -->
|
||||||
<FormKit
|
<FormKit
|
||||||
v-model="searchText"
|
v-model="searchText"
|
||||||
placeholder="Search Title..."
|
placeholder="Cari Tajuk..."
|
||||||
type="search"
|
type="search"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -152,7 +152,7 @@ const confirmModal = async () => {
|
|||||||
class="page border-2 border-gray-400 border-dashed rounded-lg"
|
class="page border-2 border-gray-400 border-dashed rounded-lg"
|
||||||
style="min-height: 250px"
|
style="min-height: 250px"
|
||||||
>
|
>
|
||||||
Add New Page
|
Tambah Halaman Baru
|
||||||
</div> -->
|
</div> -->
|
||||||
<div
|
<div
|
||||||
v-for="page in searchPages()"
|
v-for="page in searchPages()"
|
||||||
@ -180,13 +180,6 @@ const confirmModal = async () => {
|
|||||||
class="button-list flex justify-between border-t pt-4 border-gray-300"
|
class="button-list flex justify-between border-t pt-4 border-gray-300"
|
||||||
>
|
>
|
||||||
<div class="flex gap-x-2">
|
<div class="flex gap-x-2">
|
||||||
<nuxt-link
|
|
||||||
:to="`/devtool/content-editor/canvas?page=${page.name}`"
|
|
||||||
>
|
|
||||||
<rs-button variant="primary" class="!py-2 !px-3">
|
|
||||||
<Icon name="ph:paint-brush-broad"></Icon>
|
|
||||||
</rs-button>
|
|
||||||
</nuxt-link>
|
|
||||||
<nuxt-link
|
<nuxt-link
|
||||||
:to="`/devtool/content-editor/code?page=${page.name}`"
|
:to="`/devtool/content-editor/code?page=${page.name}`"
|
||||||
>
|
>
|
||||||
@ -214,18 +207,18 @@ const confirmModal = async () => {
|
|||||||
<FormKit
|
<FormKit
|
||||||
v-model="selectTemplate"
|
v-model="selectTemplate"
|
||||||
type="select"
|
type="select"
|
||||||
label="Content Template"
|
label="Templat Kandungan"
|
||||||
:options="templateOptions"
|
:options="templateOptions"
|
||||||
validation="required"
|
validation="required"
|
||||||
validation-visibility="dirty"
|
validation-visibility="dirty"
|
||||||
help="Please choose carefully the template that you want to import. This action cannot be undone."
|
help="Sila pilih dengan teliti templat yang anda ingin import. Tindakan ini tidak boleh dibatalkan."
|
||||||
/>
|
/>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<rs-button @click="showModal = false" variant="primary-text">
|
<rs-button @click="showModal = false" variant="primary-text">
|
||||||
Cancel
|
Batal
|
||||||
</rs-button>
|
</rs-button>
|
||||||
<rs-button @click="confirmModal" :disabled="!selectTemplate"
|
<rs-button @click="confirmModal" :disabled="!selectTemplate"
|
||||||
>Confirm</rs-button
|
>Sahkan</rs-button
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
</rs-modal>
|
</rs-modal>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
title: "Template Editor",
|
title: "Penyunting Templat",
|
||||||
middleware: ["auth"],
|
middleware: ["auth"],
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
});
|
});
|
||||||
@ -31,14 +31,14 @@ const searchTemplate = () => {
|
|||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<Icon class="mr-2 flex justify-center" name="ic:outline-info"></Icon
|
<Icon class="mr-2 flex justify-center" name="ic:outline-info"></Icon
|
||||||
>Info
|
>Maklumat
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #body>
|
<template #body>
|
||||||
<p class="mb-4">
|
<p class="mb-4">
|
||||||
This webpage serves as a platform for template management, enabling
|
Laman web ini berfungsi sebagai platform untuk pengurusan templat, membolehkan
|
||||||
users to select and utilize templates for rendering pages according to
|
pengguna memilih dan menggunakan templat untuk memaparkan halaman mengikut
|
||||||
their chosen design.
|
reka bentuk pilihan mereka.
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</rs-card>
|
</rs-card>
|
||||||
@ -48,7 +48,7 @@ const searchTemplate = () => {
|
|||||||
<!-- Search Button -->
|
<!-- Search Button -->
|
||||||
<FormKit
|
<FormKit
|
||||||
v-model="searchText"
|
v-model="searchText"
|
||||||
placeholder="Search Title..."
|
placeholder="Cari Tajuk..."
|
||||||
type="search"
|
type="search"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ const searchTemplate = () => {
|
|||||||
class="page border-2 border-gray-400 border-dashed rounded-lg"
|
class="page border-2 border-gray-400 border-dashed rounded-lg"
|
||||||
style="min-height: 250px"
|
style="min-height: 250px"
|
||||||
>
|
>
|
||||||
Add New Page
|
Tambah Halaman Baru
|
||||||
</div> -->
|
</div> -->
|
||||||
<div
|
<div
|
||||||
v-for="val in searchTemplate()"
|
v-for="val in searchTemplate()"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
title: "Template Viewer",
|
title: "Pelihat Templat",
|
||||||
middleware: ["auth"],
|
middleware: ["auth"],
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
});
|
});
|
||||||
|
@ -408,14 +408,14 @@ const addMenuFromList = () => {
|
|||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<Icon class="mr-2 flex justify-center" name="ic:outline-info"></Icon
|
<Icon class="mr-2 flex justify-center" name="ic:outline-info"></Icon
|
||||||
>Info
|
>Maklumat
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #body>
|
<template #body>
|
||||||
<p class="mb-4">
|
<p class="mb-4">
|
||||||
This page is used to edit the menu of the website. You can add, edit,
|
Halaman ini digunakan untuk mengedit menu laman web. Anda boleh
|
||||||
and delete menu items. You can also change the order of the menu items
|
menambah, mengedit, dan memadam item menu. Anda juga boleh mengubah
|
||||||
by dragging and dropping them.
|
susunan item menu dengan menyeret dan melepaskannya.
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</rs-card>
|
</rs-card>
|
||||||
@ -423,11 +423,11 @@ const addMenuFromList = () => {
|
|||||||
<rs-card>
|
<rs-card>
|
||||||
<div class="pt-2">
|
<div class="pt-2">
|
||||||
<rs-tab fill>
|
<rs-tab fill>
|
||||||
<rs-tab-item title="All Menu">
|
<rs-tab-item title="Semua Menu">
|
||||||
<div class="flex justify-end items-center mb-4">
|
<div class="flex justify-end items-center mb-4">
|
||||||
<rs-button @click="openModalAdd">
|
<rs-button @click="openModalAdd">
|
||||||
<Icon name="material-symbols:add" class="mr-1"></Icon>
|
<Icon name="material-symbols:add" class="mr-1"></Icon>
|
||||||
Add Menu
|
Tambah Menu
|
||||||
</rs-button>
|
</rs-button>
|
||||||
</div>
|
</div>
|
||||||
<!-- Table All Menu -->
|
<!-- Table All Menu -->
|
||||||
@ -491,18 +491,18 @@ const addMenuFromList = () => {
|
|||||||
</template>
|
</template>
|
||||||
</rs-table>
|
</rs-table>
|
||||||
</rs-tab-item>
|
</rs-tab-item>
|
||||||
<rs-tab-item title="Manage Side Menu">
|
<rs-tab-item title="Urus Menu Sisi">
|
||||||
<div class="flex justify-end items-center mb-4">
|
<div class="flex justify-end items-center mb-4">
|
||||||
<rs-button
|
<rs-button
|
||||||
class="mr-2"
|
class="mr-2"
|
||||||
@click="showCode ? (showCode = false) : (showCode = true)"
|
@click="showCode ? (showCode = false) : (showCode = true)"
|
||||||
>
|
>
|
||||||
<Icon name="ic:baseline-code" class="mr-2"></Icon>
|
<Icon name="ic:baseline-code" class="mr-2"></Icon>
|
||||||
{{ showCode ? "Hide" : "Show" }} JSON Code
|
{{ showCode ? "Sembunyikan" : "Tunjukkan" }} Kod JSON
|
||||||
</rs-button>
|
</rs-button>
|
||||||
<rs-button @click="overwriteJsonFileLocal(sideMenuList)">
|
<rs-button @click="overwriteJsonFileLocal(sideMenuList)">
|
||||||
<Icon name="mdi:content-save-outline" class="mr-2"></Icon>
|
<Icon name="mdi:content-save-outline" class="mr-2"></Icon>
|
||||||
Save Menu
|
Simpan Menu
|
||||||
</rs-button>
|
</rs-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -510,7 +510,7 @@ const addMenuFromList = () => {
|
|||||||
<div>
|
<div>
|
||||||
<FormKit
|
<FormKit
|
||||||
type="search"
|
type="search"
|
||||||
placeholder="Search Menu..."
|
placeholder="Cari Menu..."
|
||||||
outer-class="mb-5"
|
outer-class="mb-5"
|
||||||
v-model="searchInput"
|
v-model="searchInput"
|
||||||
/>
|
/>
|
||||||
@ -526,7 +526,9 @@ const addMenuFromList = () => {
|
|||||||
:sort="false"
|
:sort="false"
|
||||||
>
|
>
|
||||||
<template #item="{ element }">
|
<template #item="{ element }">
|
||||||
<rs-card class="p-4 mb-4 border-2 border-[rgb(var(--border-color))] !shadow-none">
|
<rs-card
|
||||||
|
class="p-4 mb-4 border-2 border-[rgb(var(--border-color))] !shadow-none"
|
||||||
|
>
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<p>
|
<p>
|
||||||
{{ kebabtoTitle(element.name) }} (
|
{{ kebabtoTitle(element.name) }} (
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
title: "Role List",
|
title: "Senarai Peranan",
|
||||||
middleware: ["auth"],
|
middleware: ["auth"],
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
});
|
});
|
||||||
@ -38,8 +38,8 @@ const showModalDeleteForm = ref({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const statusDropdown = ref([
|
const statusDropdown = ref([
|
||||||
{ label: "Active", value: "ACTIVE" },
|
{ label: "Aktif", value: "ACTIVE" },
|
||||||
{ label: "Inactive", value: "INACTIVE" },
|
{ label: "Tidak Aktif", value: "INACTIVE" },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const roleListbyUser = ref([]);
|
const roleListbyUser = ref([]);
|
||||||
@ -199,8 +199,8 @@ const saveUser = async () => {
|
|||||||
if (data.value.statusCode === 200) {
|
if (data.value.statusCode === 200) {
|
||||||
$swal.fire({
|
$swal.fire({
|
||||||
icon: "success",
|
icon: "success",
|
||||||
title: "Success",
|
title: "Berjaya",
|
||||||
text: "User has been added successfully",
|
text: "Pengguna telah berjaya ditambah",
|
||||||
});
|
});
|
||||||
|
|
||||||
await getUserList();
|
await getUserList();
|
||||||
@ -209,7 +209,7 @@ const saveUser = async () => {
|
|||||||
} else {
|
} else {
|
||||||
$swal.fire({
|
$swal.fire({
|
||||||
icon: "error",
|
icon: "error",
|
||||||
title: "Error",
|
title: "Ralat",
|
||||||
text: data.value.message,
|
text: data.value.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -227,8 +227,8 @@ const saveRole = async () => {
|
|||||||
$swal.fire({
|
$swal.fire({
|
||||||
position: "center",
|
position: "center",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
title: "Success",
|
title: "Berjaya",
|
||||||
text: "Role has been updated successfully",
|
text: "Peranan telah berjaya dikemas kini",
|
||||||
timer: 1000,
|
timer: 1000,
|
||||||
showConfirmButton: false,
|
showConfirmButton: false,
|
||||||
});
|
});
|
||||||
@ -242,7 +242,7 @@ const saveRole = async () => {
|
|||||||
} else {
|
} else {
|
||||||
$swal.fire({
|
$swal.fire({
|
||||||
icon: "error",
|
icon: "error",
|
||||||
title: "Error",
|
title: "Ralat",
|
||||||
text: data.value.message,
|
text: data.value.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -257,8 +257,8 @@ const saveRole = async () => {
|
|||||||
$swal.fire({
|
$swal.fire({
|
||||||
position: "center",
|
position: "center",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
title: "Success",
|
title: "Berjaya",
|
||||||
text: "Role has been added",
|
text: "Peranan telah ditambah",
|
||||||
timer: 1000,
|
timer: 1000,
|
||||||
showConfirmButton: false,
|
showConfirmButton: false,
|
||||||
});
|
});
|
||||||
@ -272,7 +272,7 @@ const saveRole = async () => {
|
|||||||
} else {
|
} else {
|
||||||
$swal.fire({
|
$swal.fire({
|
||||||
icon: "error",
|
icon: "error",
|
||||||
title: "Error",
|
title: "Ralat",
|
||||||
text: data.value.message,
|
text: data.value.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -290,8 +290,8 @@ const deleteRole = async () => {
|
|||||||
$swal.fire({
|
$swal.fire({
|
||||||
position: "center",
|
position: "center",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
title: "Success",
|
title: "Berjaya",
|
||||||
text: "User has been deleted",
|
text: "Pengguna telah dipadam",
|
||||||
timer: 1000,
|
timer: 1000,
|
||||||
showConfirmButton: false,
|
showConfirmButton: false,
|
||||||
});
|
});
|
||||||
@ -304,7 +304,7 @@ const deleteRole = async () => {
|
|||||||
$swal.fire({
|
$swal.fire({
|
||||||
position: "center",
|
position: "center",
|
||||||
icon: "error",
|
icon: "error",
|
||||||
title: "Error",
|
title: "Ralat",
|
||||||
text: data.value.message,
|
text: data.value.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -331,13 +331,13 @@ function groupRoleByUser() {
|
|||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<Icon class="mr-2 flex justify-center" name="ic:outline-info"></Icon
|
<Icon class="mr-2 flex justify-center" name="ic:outline-info"></Icon
|
||||||
>Info
|
>Maklumat
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #body>
|
<template #body>
|
||||||
<p class="mb-4">
|
<p class="mb-4">
|
||||||
This page is only accessible by admin users. You can manage users
|
Halaman ini hanya boleh diakses oleh pengguna admin. Anda boleh menguruskan pengguna
|
||||||
here. You can also add new users. You can also change user roles.
|
di sini. Anda juga boleh menambah pengguna baru. Anda juga boleh menukar peranan pengguna.
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</rs-card>
|
</rs-card>
|
||||||
@ -345,11 +345,11 @@ function groupRoleByUser() {
|
|||||||
<rs-card>
|
<rs-card>
|
||||||
<div class="pt-2">
|
<div class="pt-2">
|
||||||
<rs-tab fill>
|
<rs-tab fill>
|
||||||
<rs-tab-item title="All Role">
|
<rs-tab-item title="Semua Peranan">
|
||||||
<div class="flex justify-end items-center mb-4">
|
<div class="flex justify-end items-center mb-4">
|
||||||
<rs-button @click="openModal(null, 'add')">
|
<rs-button @click="openModal(null, 'add')">
|
||||||
<Icon name="material-symbols:add" class="mr-1"></Icon>
|
<Icon name="material-symbols:add" class="mr-1"></Icon>
|
||||||
Add Role
|
Tambah Peranan
|
||||||
</rs-button>
|
</rs-button>
|
||||||
</div>
|
</div>
|
||||||
<rs-table
|
<rs-table
|
||||||
@ -397,31 +397,31 @@ function groupRoleByUser() {
|
|||||||
</rs-card>
|
</rs-card>
|
||||||
|
|
||||||
<rs-modal
|
<rs-modal
|
||||||
:title="modalType == 'edit' ? 'Edit Role' : 'Add Role'"
|
:title="modalType == 'edit' ? 'Sunting Peranan' : 'Tambah Peranan'"
|
||||||
ok-title="Save"
|
ok-title="Simpan"
|
||||||
:ok-callback="saveRole"
|
:ok-callback="saveRole"
|
||||||
v-model="showModal"
|
v-model="showModal"
|
||||||
>
|
>
|
||||||
<FormKit
|
<FormKit
|
||||||
type="text"
|
type="text"
|
||||||
v-model="showModalForm.name"
|
v-model="showModalForm.name"
|
||||||
label="Name"
|
label="Nama"
|
||||||
validation="required"
|
validation="required"
|
||||||
validation-visibility="live"
|
validation-visibility="live"
|
||||||
/>
|
/>
|
||||||
<FormKit
|
<FormKit
|
||||||
type="textarea"
|
type="textarea"
|
||||||
v-model="showModalForm.description"
|
v-model="showModalForm.description"
|
||||||
label="Description"
|
label="Penerangan"
|
||||||
/>
|
/>
|
||||||
<div class="flex justify-between items-center mb-2">
|
<div class="flex justify-between items-center mb-2">
|
||||||
<label
|
<label
|
||||||
class="formkit-label font-semibold text-gray-700 dark:text-gray-200 blockfont-semibold text-sm formkit-invalid:text-red-500 dark:formkit-invalid:text-danger"
|
class="formkit-label font-semibold text-gray-700 dark:text-gray-200 blockfont-semibold text-sm formkit-invalid:text-red-500 dark:formkit-invalid:text-danger"
|
||||||
for="input_4"
|
for="input_4"
|
||||||
>
|
>
|
||||||
Users
|
Pengguna
|
||||||
</label>
|
</label>
|
||||||
<rs-button size="sm" @click="openModalUser"> Add User </rs-button>
|
<rs-button size="sm" @click="openModalUser"> Tambah Pengguna </rs-button>
|
||||||
</div>
|
</div>
|
||||||
<v-select
|
<v-select
|
||||||
class="formkit-vselect"
|
class="formkit-vselect"
|
||||||
@ -432,7 +432,7 @@ function groupRoleByUser() {
|
|||||||
<FormKit
|
<FormKit
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
v-model="checkAllUser"
|
v-model="checkAllUser"
|
||||||
label="All Users"
|
label="Semua Pengguna"
|
||||||
input-class="icon-check"
|
input-class="icon-check"
|
||||||
/>
|
/>
|
||||||
<FormKit
|
<FormKit
|
||||||
@ -446,9 +446,9 @@ function groupRoleByUser() {
|
|||||||
|
|
||||||
<!-- Modal Role -->
|
<!-- Modal Role -->
|
||||||
<rs-modal
|
<rs-modal
|
||||||
title="Add User"
|
title="Tambah Pengguna"
|
||||||
ok-title="Save"
|
ok-title="Simpan"
|
||||||
cancel-title="Back"
|
cancel-title="Kembali"
|
||||||
:cancel-callback="closeModalUser"
|
:cancel-callback="closeModalUser"
|
||||||
:ok-callback="saveUser"
|
:ok-callback="saveUser"
|
||||||
v-model="showModalUser"
|
v-model="showModalUser"
|
||||||
@ -457,19 +457,19 @@ function groupRoleByUser() {
|
|||||||
type="text"
|
type="text"
|
||||||
v-model="showModalUserForm.username"
|
v-model="showModalUserForm.username"
|
||||||
name="username"
|
name="username"
|
||||||
label="Username"
|
label="Nama Pengguna"
|
||||||
/>
|
/>
|
||||||
<FormKit
|
<FormKit
|
||||||
type="text"
|
type="text"
|
||||||
v-model="showModalUserForm.fullname"
|
v-model="showModalUserForm.fullname"
|
||||||
name="fullname"
|
name="fullname"
|
||||||
label="Fullname"
|
label="Nama Penuh"
|
||||||
/>
|
/>
|
||||||
<FormKit
|
<FormKit
|
||||||
type="text"
|
type="text"
|
||||||
v-model="showModalUserForm.email"
|
v-model="showModalUserForm.email"
|
||||||
name="email"
|
name="email"
|
||||||
label="Email"
|
label="E-mel"
|
||||||
validation="email"
|
validation="email"
|
||||||
validation-visibility="dirty"
|
validation-visibility="dirty"
|
||||||
/>
|
/>
|
||||||
@ -477,7 +477,7 @@ function groupRoleByUser() {
|
|||||||
type="mask"
|
type="mask"
|
||||||
v-model="showModalUserForm.phone"
|
v-model="showModalUserForm.phone"
|
||||||
name="phone"
|
name="phone"
|
||||||
label="Phone"
|
label="Telefon"
|
||||||
mask="###########"
|
mask="###########"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -492,14 +492,14 @@ function groupRoleByUser() {
|
|||||||
|
|
||||||
<!-- Modal Delete Confirmation -->
|
<!-- Modal Delete Confirmation -->
|
||||||
<rs-modal
|
<rs-modal
|
||||||
title="Delete Confirmation"
|
title="Pengesahan Padam"
|
||||||
ok-title="Yes"
|
ok-title="Ya"
|
||||||
cancel-title="No"
|
cancel-title="Tidak"
|
||||||
:ok-callback="deleteRole"
|
:ok-callback="deleteRole"
|
||||||
v-model="showModalDelete"
|
v-model="showModalDelete"
|
||||||
>
|
>
|
||||||
<p>
|
<p>
|
||||||
Are you sure want to delete this role ({{ showModalDeleteForm.name }})?
|
Adakah anda pasti mahu memadam peranan ini ({{ showModalDeleteForm.name }})?
|
||||||
</p>
|
</p>
|
||||||
</rs-modal>
|
</rs-modal>
|
||||||
</div>
|
</div>
|
||||||
|
@ -37,8 +37,8 @@ const showModalDeleteForm = ref({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const statusDropdown = ref([
|
const statusDropdown = ref([
|
||||||
{ label: "Active", value: "ACTIVE" },
|
{ label: "Aktif", value: "ACTIVE" },
|
||||||
{ label: "Inactive", value: "INACTIVE" },
|
{ label: "Tidak Aktif", value: "INACTIVE" },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const checkAllRole = ref(false);
|
const checkAllRole = ref(false);
|
||||||
@ -195,8 +195,8 @@ const saveUser = async () => {
|
|||||||
$swal.fire({
|
$swal.fire({
|
||||||
position: "center",
|
position: "center",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
title: "Success",
|
title: "Berjaya",
|
||||||
text: "User has been added",
|
text: "Pengguna telah ditambah",
|
||||||
timer: 1000,
|
timer: 1000,
|
||||||
showConfirmButton: false,
|
showConfirmButton: false,
|
||||||
});
|
});
|
||||||
@ -210,7 +210,7 @@ const saveUser = async () => {
|
|||||||
$swal.fire({
|
$swal.fire({
|
||||||
position: "center",
|
position: "center",
|
||||||
icon: "error",
|
icon: "error",
|
||||||
title: "Error",
|
title: "Ralat",
|
||||||
text: data.value.message,
|
text: data.value.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -225,8 +225,8 @@ const saveUser = async () => {
|
|||||||
$swal.fire({
|
$swal.fire({
|
||||||
position: "center",
|
position: "center",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
title: "Success",
|
title: "Berjaya",
|
||||||
text: "User has been updated",
|
text: "Pengguna telah dikemaskini",
|
||||||
timer: 1000,
|
timer: 1000,
|
||||||
showConfirmButton: false,
|
showConfirmButton: false,
|
||||||
});
|
});
|
||||||
@ -240,7 +240,7 @@ const saveUser = async () => {
|
|||||||
$swal.fire({
|
$swal.fire({
|
||||||
position: "center",
|
position: "center",
|
||||||
icon: "error",
|
icon: "error",
|
||||||
title: "Error",
|
title: "Ralat",
|
||||||
text: data.value.message,
|
text: data.value.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -258,8 +258,8 @@ const deleteUser = async () => {
|
|||||||
$swal.fire({
|
$swal.fire({
|
||||||
position: "center",
|
position: "center",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
title: "Success",
|
title: "Berjaya",
|
||||||
text: "User has been deleted",
|
text: "Pengguna telah dipadam",
|
||||||
timer: 1000,
|
timer: 1000,
|
||||||
showConfirmButton: false,
|
showConfirmButton: false,
|
||||||
});
|
});
|
||||||
@ -272,7 +272,7 @@ const deleteUser = async () => {
|
|||||||
$swal.fire({
|
$swal.fire({
|
||||||
position: "center",
|
position: "center",
|
||||||
icon: "error",
|
icon: "error",
|
||||||
title: "Error",
|
title: "Ralat",
|
||||||
text: data.value.message,
|
text: data.value.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -298,7 +298,7 @@ const saveRole = async () => {
|
|||||||
if (data.value.statusCode === 200) {
|
if (data.value.statusCode === 200) {
|
||||||
$swal.fire({
|
$swal.fire({
|
||||||
position: "center",
|
position: "center",
|
||||||
title: "Success",
|
title: "Berjaya",
|
||||||
text: data.value.message,
|
text: data.value.message,
|
||||||
icon: "success",
|
icon: "success",
|
||||||
timer: 1000,
|
timer: 1000,
|
||||||
@ -310,7 +310,7 @@ const saveRole = async () => {
|
|||||||
} else {
|
} else {
|
||||||
$swal.fire({
|
$swal.fire({
|
||||||
position: "center",
|
position: "center",
|
||||||
title: "Error",
|
title: "Ralat",
|
||||||
text: data.value.message,
|
text: data.value.message,
|
||||||
icon: "error",
|
icon: "error",
|
||||||
});
|
});
|
||||||
@ -338,13 +338,13 @@ function groupUserByRole() {
|
|||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<Icon class="mr-2 flex justify-center" name="ic:outline-info"></Icon
|
<Icon class="mr-2 flex justify-center" name="ic:outline-info"></Icon
|
||||||
>Info
|
>Maklumat
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #body>
|
<template #body>
|
||||||
<p class="mb-4">
|
<p class="mb-4">
|
||||||
This page is only accessible by admin users. You can manage users
|
Halaman ini hanya boleh diakses oleh pengguna admin. Anda boleh menguruskan pengguna
|
||||||
here. You can also add new users. You can also change user roles.
|
di sini. Anda juga boleh menambah pengguna baru. Anda juga boleh menukar peranan pengguna.
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</rs-card>
|
</rs-card>
|
||||||
@ -352,11 +352,11 @@ function groupUserByRole() {
|
|||||||
<rs-card>
|
<rs-card>
|
||||||
<div class="pt-2">
|
<div class="pt-2">
|
||||||
<rs-tab fill>
|
<rs-tab fill>
|
||||||
<rs-tab-item title="All User">
|
<rs-tab-item title="Semua Pengguna">
|
||||||
<div class="flex justify-end items-center mb-4">
|
<div class="flex justify-end items-center mb-4">
|
||||||
<rs-button @click="openModal(null, 'add')">
|
<rs-button @click="openModal(null, 'add')">
|
||||||
<Icon name="material-symbols:add" class="mr-1"></Icon>
|
<Icon name="material-symbols:add" class="mr-1"></Icon>
|
||||||
Add User
|
Tambah Pengguna
|
||||||
</rs-button>
|
</rs-button>
|
||||||
</div>
|
</div>
|
||||||
<rs-table
|
<rs-table
|
||||||
@ -405,8 +405,8 @@ function groupUserByRole() {
|
|||||||
</rs-card>
|
</rs-card>
|
||||||
|
|
||||||
<rs-modal
|
<rs-modal
|
||||||
:title="modalType == 'edit' ? 'Edit User' : 'Add User'"
|
:title="modalType == 'edit' ? 'Sunting Pengguna' : 'Tambah Pengguna'"
|
||||||
ok-title="Save"
|
ok-title="Simpan"
|
||||||
:ok-callback="saveUser"
|
:ok-callback="saveUser"
|
||||||
v-model="showModal"
|
v-model="showModal"
|
||||||
>
|
>
|
||||||
@ -414,20 +414,20 @@ function groupUserByRole() {
|
|||||||
type="text"
|
type="text"
|
||||||
v-model="showModalForm.username"
|
v-model="showModalForm.username"
|
||||||
name="username"
|
name="username"
|
||||||
label="Username"
|
label="Nama Pengguna"
|
||||||
:disabled="modalType == 'edit' ? true : false"
|
:disabled="modalType == 'edit' ? true : false"
|
||||||
/>
|
/>
|
||||||
<FormKit
|
<FormKit
|
||||||
type="text"
|
type="text"
|
||||||
v-model="showModalForm.fullname"
|
v-model="showModalForm.fullname"
|
||||||
name="fullname"
|
name="fullname"
|
||||||
label="Fullname"
|
label="Nama Penuh"
|
||||||
/>
|
/>
|
||||||
<FormKit
|
<FormKit
|
||||||
type="text"
|
type="text"
|
||||||
v-model="showModalForm.email"
|
v-model="showModalForm.email"
|
||||||
name="email"
|
name="email"
|
||||||
label="Email"
|
label="E-mel"
|
||||||
validation="email"
|
validation="email"
|
||||||
validation-visibility="dirty"
|
validation-visibility="dirty"
|
||||||
/>
|
/>
|
||||||
@ -435,7 +435,7 @@ function groupUserByRole() {
|
|||||||
type="mask"
|
type="mask"
|
||||||
v-model="showModalForm.phone"
|
v-model="showModalForm.phone"
|
||||||
name="phone"
|
name="phone"
|
||||||
label="Phone"
|
label="Telefon"
|
||||||
mask="###########"
|
mask="###########"
|
||||||
/>
|
/>
|
||||||
<div class="flex justify-between items-center mb-2">
|
<div class="flex justify-between items-center mb-2">
|
||||||
@ -443,9 +443,9 @@ function groupUserByRole() {
|
|||||||
class="formkit-label flex items-center gap-x-4 font-semibold text-gray-700 dark:text-gray-200 blockfont-semibold text-sm formkit-invalid:text-red-500 dark:formkit-invalid:text-danger"
|
class="formkit-label flex items-center gap-x-4 font-semibold text-gray-700 dark:text-gray-200 blockfont-semibold text-sm formkit-invalid:text-red-500 dark:formkit-invalid:text-danger"
|
||||||
for="input_4"
|
for="input_4"
|
||||||
>
|
>
|
||||||
Role
|
Peranan
|
||||||
</label>
|
</label>
|
||||||
<rs-button size="sm" @click="openModalRole"> Add Role </rs-button>
|
<rs-button size="sm" @click="openModalRole"> Tambah Peranan </rs-button>
|
||||||
</div>
|
</div>
|
||||||
<v-select
|
<v-select
|
||||||
class="formkit-vselect"
|
class="formkit-vselect"
|
||||||
@ -456,7 +456,7 @@ function groupUserByRole() {
|
|||||||
<FormKit
|
<FormKit
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
v-model="checkAllRole"
|
v-model="checkAllRole"
|
||||||
label="All Role"
|
label="Semua Peranan"
|
||||||
input-class="icon-check"
|
input-class="icon-check"
|
||||||
/>
|
/>
|
||||||
<FormKit
|
<FormKit
|
||||||
@ -470,9 +470,9 @@ function groupUserByRole() {
|
|||||||
|
|
||||||
<!-- Modal Role -->
|
<!-- Modal Role -->
|
||||||
<rs-modal
|
<rs-modal
|
||||||
title="Add Role"
|
title="Tambah Peranan"
|
||||||
ok-title="Save"
|
ok-title="Simpan"
|
||||||
cancel-title="Back"
|
cancel-title="Kembali"
|
||||||
:cancel-callback="closeModalRole"
|
:cancel-callback="closeModalRole"
|
||||||
:ok-callback="saveRole"
|
:ok-callback="saveRole"
|
||||||
v-model="showModalRole"
|
v-model="showModalRole"
|
||||||
@ -480,27 +480,27 @@ function groupUserByRole() {
|
|||||||
<FormKit
|
<FormKit
|
||||||
type="text"
|
type="text"
|
||||||
v-model="showModalRoleForm.role"
|
v-model="showModalRoleForm.role"
|
||||||
label="Name"
|
label="Nama"
|
||||||
validation="required"
|
validation="required"
|
||||||
validation-visibility="live"
|
validation-visibility="live"
|
||||||
/>
|
/>
|
||||||
<FormKit
|
<FormKit
|
||||||
type="textarea"
|
type="textarea"
|
||||||
v-model="showModalRoleForm.description"
|
v-model="showModalRoleForm.description"
|
||||||
label="Description"
|
label="Penerangan"
|
||||||
/>
|
/>
|
||||||
</rs-modal>
|
</rs-modal>
|
||||||
|
|
||||||
<!-- Modal Delete Confirmation -->
|
<!-- Modal Delete Confirmation -->
|
||||||
<rs-modal
|
<rs-modal
|
||||||
title="Delete Confirmation"
|
title="Pengesahan Padam"
|
||||||
ok-title="Yes"
|
ok-title="Ya"
|
||||||
cancel-title="No"
|
cancel-title="Tidak"
|
||||||
:ok-callback="deleteUser"
|
:ok-callback="deleteUser"
|
||||||
v-model="showModalDelete"
|
v-model="showModalDelete"
|
||||||
>
|
>
|
||||||
<p>
|
<p>
|
||||||
Are you sure want to delete this user ({{
|
Adakah anda pasti mahu memadam pengguna ini ({{
|
||||||
showModalDeleteForm.username
|
showModalDeleteForm.username
|
||||||
}})?
|
}})?
|
||||||
</p>
|
</p>
|
||||||
|
233
pages/prototype/for-01/kemaskini-daftar/index.vue
Normal file
233
pages/prototype/for-01/kemaskini-daftar/index.vue
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
<script setup>
|
||||||
|
definePageMeta({
|
||||||
|
title: "Kemaskini Daftar FR2",
|
||||||
|
breadcrumb: [
|
||||||
|
{
|
||||||
|
name: "Kemaskini Daftar FR2",
|
||||||
|
type: "current",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const { $swal } = useNuxtApp();
|
||||||
|
|
||||||
|
const caseId = ref("");
|
||||||
|
const equipmentCondition = ref(false);
|
||||||
|
const officerQualification = ref(false);
|
||||||
|
const methodApplicability = ref(false);
|
||||||
|
const externalSupport = ref(false);
|
||||||
|
const taskAcceptance = ref("");
|
||||||
|
const officerComments = ref("");
|
||||||
|
const showForm = ref(false);
|
||||||
|
|
||||||
|
const verifyCase = async () => {
|
||||||
|
if (!caseId.value) {
|
||||||
|
$swal.fire({
|
||||||
|
icon: "error",
|
||||||
|
title: "ID Kes diperlukan",
|
||||||
|
text: "Sila masukkan ID Kes untuk menyemak.",
|
||||||
|
timer: 3000,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
$swal.fire({
|
||||||
|
icon: "success",
|
||||||
|
title: "ID Kes disahkan",
|
||||||
|
text: "Maklumat kes telah berjaya diambil.",
|
||||||
|
timer: 3000,
|
||||||
|
});
|
||||||
|
showForm.value = true;
|
||||||
|
} catch (error) {
|
||||||
|
$swal.fire({
|
||||||
|
icon: "error",
|
||||||
|
title: "Gagal mengesahkan ID Kes",
|
||||||
|
text: "Sila cuba lagi atau hubungi pentadbir sistem.",
|
||||||
|
timer: 3000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateForm = async () => {
|
||||||
|
if (!validateForm()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
$swal.fire({
|
||||||
|
icon: "success",
|
||||||
|
title: "Rekod telah berjaya dikemas kini",
|
||||||
|
text: "Maklumat telah dikemas kini dalam sistem.",
|
||||||
|
timer: 3000,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
$swal.fire({
|
||||||
|
icon: "error",
|
||||||
|
title: "Gagal mengemas kini rekod",
|
||||||
|
text: "Sila cuba lagi atau hubungi pentadbir sistem.",
|
||||||
|
timer: 3000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitForm = async () => {
|
||||||
|
if (!validateForm()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
$swal.fire({
|
||||||
|
icon: "success",
|
||||||
|
title: "Rekod telah berjaya disahkan",
|
||||||
|
text: "Maklumat telah disahkan dan disimpan dalam sistem.",
|
||||||
|
timer: 3000,
|
||||||
|
});
|
||||||
|
router.push("/dashboard");
|
||||||
|
} catch (error) {
|
||||||
|
$swal.fire({
|
||||||
|
icon: "error",
|
||||||
|
title: "Gagal mengesahkan rekod",
|
||||||
|
text: "Sila cuba lagi atau hubungi pentadbir sistem.",
|
||||||
|
timer: 3000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateForm = () => {
|
||||||
|
if (
|
||||||
|
!equipmentCondition.value ||
|
||||||
|
!officerQualification.value ||
|
||||||
|
!methodApplicability.value ||
|
||||||
|
!taskAcceptance.value
|
||||||
|
) {
|
||||||
|
$swal.fire({
|
||||||
|
icon: "error",
|
||||||
|
title: "Borang tidak lengkap",
|
||||||
|
text: "Sila lengkapkan semua maklumat yang diperlukan.",
|
||||||
|
timer: 3000,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (taskAcceptance.value === "Tidak" && !officerComments.value) {
|
||||||
|
$swal.fire({
|
||||||
|
icon: "error",
|
||||||
|
title: "Komen diperlukan",
|
||||||
|
text: "Sila berikan komen kerana tugas tidak diterima.",
|
||||||
|
timer: 3000,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="">
|
||||||
|
<LayoutsBreadcrumb class="mb-6" />
|
||||||
|
|
||||||
|
<RsCard class="mb-6 shadow-lg">
|
||||||
|
<template #header>
|
||||||
|
<h2 class="text-2xl">Kemaskini Daftar FR2</h2>
|
||||||
|
</template>
|
||||||
|
<template #body>
|
||||||
|
<div class="space-y-8">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-medium mb-4 text-gray-700">
|
||||||
|
Pengesahan ID Kes
|
||||||
|
</h3>
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<FormKit
|
||||||
|
type="text"
|
||||||
|
name="caseId"
|
||||||
|
label="ID Kes"
|
||||||
|
validation="required"
|
||||||
|
:validation-messages="{
|
||||||
|
required: 'Sila masukkan ID Kes',
|
||||||
|
}"
|
||||||
|
v-model="caseId"
|
||||||
|
class="flex-grow"
|
||||||
|
:classes="{
|
||||||
|
outer: 'mb-0',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<RsButton @click="verifyCase" variant="primary" class="mb-1"
|
||||||
|
>Semak</RsButton
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FormKit
|
||||||
|
v-if="showForm"
|
||||||
|
type="form"
|
||||||
|
@submit="submitForm"
|
||||||
|
:actions="false"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-medium mb-4 text-gray-700">Borang FR2</h3>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<FormKit
|
||||||
|
type="checkbox"
|
||||||
|
name="equipmentCondition"
|
||||||
|
label="Peralatan dalam keadaan baik untuk analisis/pemeriksaan"
|
||||||
|
v-model="equipmentCondition"
|
||||||
|
/>
|
||||||
|
<FormKit
|
||||||
|
type="checkbox"
|
||||||
|
name="officerQualification"
|
||||||
|
label="Pegawai berkelayakan untuk analisis/pemeriksaan"
|
||||||
|
v-model="officerQualification"
|
||||||
|
/>
|
||||||
|
<FormKit
|
||||||
|
type="checkbox"
|
||||||
|
name="methodApplicability"
|
||||||
|
label="Kaedah boleh dilaksanakan dan diterima untuk analisis"
|
||||||
|
v-model="methodApplicability"
|
||||||
|
/>
|
||||||
|
<FormKit
|
||||||
|
type="checkbox"
|
||||||
|
name="externalSupport"
|
||||||
|
label="Sokongan luar diperlukan"
|
||||||
|
v-model="externalSupport"
|
||||||
|
/>
|
||||||
|
<FormKit
|
||||||
|
type="select"
|
||||||
|
name="taskAcceptance"
|
||||||
|
label="Penerimaan Tugas"
|
||||||
|
:options="[
|
||||||
|
{ label: 'Ya', value: 'Ya' },
|
||||||
|
{ label: 'Tidak', value: 'Tidak' },
|
||||||
|
]"
|
||||||
|
validation="required"
|
||||||
|
:validation-messages="{
|
||||||
|
required: 'Sila pilih penerimaan tugas',
|
||||||
|
}"
|
||||||
|
v-model="taskAcceptance"
|
||||||
|
/>
|
||||||
|
<FormKit
|
||||||
|
type="textarea"
|
||||||
|
name="officerComments"
|
||||||
|
label="Komen Pegawai"
|
||||||
|
v-model="officerComments"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-8 flex justify-end space-x-4">
|
||||||
|
<RsButton @click="updateForm" variant="secondary"
|
||||||
|
>Kemas Kini</RsButton
|
||||||
|
>
|
||||||
|
<!-- <RsButton type="submit" variant="primary">Sahkan</RsButton> -->
|
||||||
|
</div>
|
||||||
|
</FormKit>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</RsCard>
|
||||||
|
</div>
|
||||||
|
</template>
|
334
pages/prototype/for-01/permohonan/index.vue
Normal file
334
pages/prototype/for-01/permohonan/index.vue
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
<script setup>
|
||||||
|
definePageMeta({
|
||||||
|
title: "Permohonan Online",
|
||||||
|
breadcrumb: [
|
||||||
|
{
|
||||||
|
name: "Permohonan Online",
|
||||||
|
type: "current",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const { $swal } = useNuxtApp();
|
||||||
|
|
||||||
|
const applicantRank = ref("");
|
||||||
|
const applicantName = ref("");
|
||||||
|
const applicantOfficerNumber = ref("");
|
||||||
|
const sameAsSender = ref(false);
|
||||||
|
const showConfirmationModal = ref(false);
|
||||||
|
const showDateTimeModal = ref(false);
|
||||||
|
const availableTimeSlots = ref([]);
|
||||||
|
const formData = ref({});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// Fetch applicant details from the system
|
||||||
|
fetchApplicantDetails();
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchApplicantDetails = async () => {
|
||||||
|
try {
|
||||||
|
// Simulated fetch of applicant details
|
||||||
|
applicantRank.value = "Inspector";
|
||||||
|
applicantName.value = "John Doe";
|
||||||
|
applicantOfficerNumber.value = "123456";
|
||||||
|
} catch (error) {
|
||||||
|
$swal.fire({
|
||||||
|
icon: "error",
|
||||||
|
title: "Gagal mendapatkan maklumat pemohon",
|
||||||
|
text: "Sila cuba lagi.",
|
||||||
|
timer: 5000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleSenderDetails = (value) => {
|
||||||
|
sameAsSender.value = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitForm = (formData) => {
|
||||||
|
// Store form data for later use
|
||||||
|
formData.value = formData;
|
||||||
|
showConfirmationModal.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmSubmission = async () => {
|
||||||
|
showConfirmationModal.value = false;
|
||||||
|
try {
|
||||||
|
// Simulated form submission
|
||||||
|
$swal.fire({
|
||||||
|
icon: "success",
|
||||||
|
title: "Permohonan pemeriksaan forensik telah dihantar",
|
||||||
|
timer: 5000,
|
||||||
|
});
|
||||||
|
showDateTimeModal.value = true;
|
||||||
|
fetchAvailableTimeSlots();
|
||||||
|
} catch (error) {
|
||||||
|
$swal.fire({
|
||||||
|
icon: "error",
|
||||||
|
title: "Gagal menghantar permohonan",
|
||||||
|
text: "Sila cuba lagi.",
|
||||||
|
timer: 5000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchAvailableTimeSlots = async () => {
|
||||||
|
try {
|
||||||
|
// Simulated fetch of available time slots
|
||||||
|
availableTimeSlots.value = [
|
||||||
|
{ label: "9:00 AM", value: "09:00" },
|
||||||
|
{ label: "10:00 AM", value: "10:00" },
|
||||||
|
{ label: "11:00 AM", value: "11:00" },
|
||||||
|
];
|
||||||
|
} catch (error) {
|
||||||
|
$swal.fire({
|
||||||
|
icon: "error",
|
||||||
|
title: "Gagal mendapatkan slot masa yang tersedia",
|
||||||
|
text: "Sila cuba lagi.",
|
||||||
|
timer: 5000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmDateTimeSlot = async () => {
|
||||||
|
try {
|
||||||
|
// Simulated confirmation of date and time slot
|
||||||
|
const data = { caseId: "FOR-2023-001" };
|
||||||
|
$swal.fire({
|
||||||
|
icon: "success",
|
||||||
|
title: "Janji temu telah disahkan",
|
||||||
|
text: `Nombor rujukan kes: ${data.caseId}`,
|
||||||
|
timer: 5000,
|
||||||
|
});
|
||||||
|
showDateTimeModal.value = false;
|
||||||
|
router.push("/dashboard"); // Redirect to dashboard or confirmation page
|
||||||
|
} catch (error) {
|
||||||
|
$swal.fire({
|
||||||
|
icon: "error",
|
||||||
|
title: "Gagal mengesahkan janji temu",
|
||||||
|
text: "Sila cuba lagi.",
|
||||||
|
timer: 5000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<LayoutsBreadcrumb class="mb-6" />
|
||||||
|
|
||||||
|
<FormKit type="form" @submit="submitForm" :actions="false">
|
||||||
|
<!-- Butir Permohonan Card -->
|
||||||
|
<RsCard class="mb-6">
|
||||||
|
<template #header>
|
||||||
|
<h2 class="text-2xl font-semibold">Butir Permohonan</h2>
|
||||||
|
</template>
|
||||||
|
<template #body>
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-medium mb-3">Butir-butir Pemohon</h3>
|
||||||
|
<div class="bg-gray-100 p-4 rounded-lg">
|
||||||
|
<p>
|
||||||
|
<span class="font-medium">Nama:</span> {{ applicantName }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="font-medium">Pangkat:</span> {{ applicantRank }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="font-medium">Nombor Pegawai:</span>
|
||||||
|
{{ applicantOfficerNumber }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-medium mb-3">
|
||||||
|
Butir-butir Penghantar Barang Kes
|
||||||
|
</h3>
|
||||||
|
<FormKit
|
||||||
|
type="checkbox"
|
||||||
|
name="sameAsSender"
|
||||||
|
label="Penghantar Barang Kes Sama Dengan Pemohon"
|
||||||
|
v-model="sameAsSender"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div v-if="!sameAsSender" class="mt-4 space-y-4">
|
||||||
|
<FormKit
|
||||||
|
type="text"
|
||||||
|
name="senderName"
|
||||||
|
label="Nama Penghantar Barang Kes"
|
||||||
|
validation="required"
|
||||||
|
:validation-messages="{
|
||||||
|
required: 'Sila masukkan nama penghantar barang kes',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<FormKit
|
||||||
|
type="text"
|
||||||
|
name="senderRank"
|
||||||
|
label="Pangkat Penghantar Barang Kes"
|
||||||
|
validation="required"
|
||||||
|
:validation-messages="{
|
||||||
|
required: 'Sila masukkan pangkat penghantar barang kes',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<FormKit
|
||||||
|
type="text"
|
||||||
|
name="senderOfficerNumber"
|
||||||
|
label="Nombor Pegawai Penghantar Barang Kes"
|
||||||
|
validation="required|number|length:6"
|
||||||
|
:validation-messages="{
|
||||||
|
required:
|
||||||
|
'Sila masukkan nombor pegawai penghantar barang kes',
|
||||||
|
number: 'Nombor pegawai mesti dalam bentuk nombor',
|
||||||
|
length: 'Nombor pegawai mesti mempunyai 6 digit',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</RsCard>
|
||||||
|
|
||||||
|
<!-- Maklumat Kes Card -->
|
||||||
|
<RsCard class="mb-6">
|
||||||
|
<template #header>
|
||||||
|
<h2 class="text-2xl font-semibold">Maklumat Kes</h2>
|
||||||
|
</template>
|
||||||
|
<template #body>
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-medium mb-3">Maklumat Barang Kes</h3>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<FormKit
|
||||||
|
type="select"
|
||||||
|
name="jenisBarang"
|
||||||
|
label="Jenis Barang"
|
||||||
|
:options="[
|
||||||
|
{ label: 'Pasport', value: 'pasport' },
|
||||||
|
{ label: 'Malpass', value: 'malpass' },
|
||||||
|
{ label: 'Cap Keselamatan', value: 'capKeselamatan' },
|
||||||
|
{ label: 'Cap Jari', value: 'capJari' },
|
||||||
|
{ label: 'Pemeriksaan Siber', value: 'pemeriksaanSiber' },
|
||||||
|
{ label: 'Tulisan Tangan', value: 'tulisanTangan' },
|
||||||
|
{ label: 'I-Kad', value: 'iKad' },
|
||||||
|
{ label: 'Lain-lain', value: 'lainLain' },
|
||||||
|
]"
|
||||||
|
validation="required"
|
||||||
|
:validation-messages="{
|
||||||
|
required: 'Sila pilih jenis barang',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<FormKit
|
||||||
|
type="text"
|
||||||
|
name="tandaBarang"
|
||||||
|
label="Tanda Barang"
|
||||||
|
validation="required"
|
||||||
|
:validation-messages="{
|
||||||
|
required: 'Sila masukkan tanda barang',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<FormKit
|
||||||
|
type="text"
|
||||||
|
name="keadaanBarang"
|
||||||
|
label="Keadaan Barang"
|
||||||
|
validation="required"
|
||||||
|
:validation-messages="{
|
||||||
|
required: 'Sila masukkan keadaan barang',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<FormKit
|
||||||
|
type="number"
|
||||||
|
name="kuantitiBarang"
|
||||||
|
label="Kuantiti Barang"
|
||||||
|
validation="required|number|min:1"
|
||||||
|
:validation-messages="{
|
||||||
|
required: 'Sila masukkan kuantiti barang',
|
||||||
|
number: 'Kuantiti mesti dalam bentuk nombor',
|
||||||
|
min: 'Kuantiti mesti sekurang-kurangnya 1',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-medium mb-3">Maklumat Tambahan</h3>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<FormKit
|
||||||
|
type="textarea"
|
||||||
|
name="ringkasanKes"
|
||||||
|
label="Ringkasan Kenyataan Kes"
|
||||||
|
/>
|
||||||
|
<FormKit
|
||||||
|
type="text"
|
||||||
|
name="nomorKertasSiasatan"
|
||||||
|
label="Nombor Kertas Siasatan"
|
||||||
|
/>
|
||||||
|
<FormKit
|
||||||
|
type="text"
|
||||||
|
name="nomorLaporanPolis"
|
||||||
|
label="Nombor Laporan Polis"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</RsCard>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<FormKit
|
||||||
|
type="submit"
|
||||||
|
label="Hantar Permohonan"
|
||||||
|
input-class="text-white font-bold py-2 px-4 rounded w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</FormKit>
|
||||||
|
|
||||||
|
<!-- Confirmation Modal -->
|
||||||
|
<RsModal v-model="showConfirmationModal" title="Pengesahan Permohonan">
|
||||||
|
<template #body>
|
||||||
|
<p>Adakah anda pasti untuk menghantar permohonan ini?</p>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<RsButton @click="showConfirmationModal = false" variant="secondary"
|
||||||
|
>Kembali</RsButton
|
||||||
|
>
|
||||||
|
<RsButton @click="confirmSubmission" variant="primary">Sahkan</RsButton>
|
||||||
|
</template>
|
||||||
|
</RsModal>
|
||||||
|
|
||||||
|
<!-- Date and Time Slot Selection Modal -->
|
||||||
|
<RsModal v-model="showDateTimeModal" title="Pilih Tarikh dan Slot Masa">
|
||||||
|
<template #body>
|
||||||
|
<FormKit
|
||||||
|
type="date"
|
||||||
|
name="appointmentDate"
|
||||||
|
label="Tarikh Janji Temu"
|
||||||
|
validation="required|after:today"
|
||||||
|
:validation-messages="{
|
||||||
|
required: 'Sila pilih tarikh janji temu',
|
||||||
|
after: 'Tarikh janji temu mestilah selepas tarikh hari ini',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<FormKit
|
||||||
|
type="select"
|
||||||
|
name="timeSlot"
|
||||||
|
label="Slot Masa"
|
||||||
|
:options="availableTimeSlots"
|
||||||
|
validation="required"
|
||||||
|
:validation-messages="{
|
||||||
|
required: 'Sila pilih slot masa',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<RsButton @click="showDateTimeModal = false" variant="secondary"
|
||||||
|
>Kembali</RsButton
|
||||||
|
>
|
||||||
|
<RsButton @click="confirmDateTimeSlot" variant="primary"
|
||||||
|
>Sahkan</RsButton
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</RsModal>
|
||||||
|
</div>
|
||||||
|
</template>
|
193
pages/senarai-mesej/index.vue
Normal file
193
pages/senarai-mesej/index.vue
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
<script setup>
|
||||||
|
definePageMeta({
|
||||||
|
title: "Senarai Mesej",
|
||||||
|
breadcrumb: [
|
||||||
|
{
|
||||||
|
name: "Senarai Mesej",
|
||||||
|
type: "current",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const messages = ref([
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
sender: "Admin",
|
||||||
|
subject: "Selamat Datang",
|
||||||
|
preview: "Selamat datang ke sistem mesej kami...",
|
||||||
|
content:
|
||||||
|
"Selamat datang ke sistem mesej kami. Kami berharap anda akan menikmati pengalaman menggunakan sistem ini. Jika ada sebarang pertanyaan, sila hubungi kami.",
|
||||||
|
date: "1-50 daripada 528",
|
||||||
|
isRead: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
sender: "Spotify",
|
||||||
|
subject: "Tawaran Istimewa untuk Anda",
|
||||||
|
preview: "Dapatkan langganan premium dengan harga istimewa...",
|
||||||
|
content:
|
||||||
|
"Dapatkan langganan premium dengan harga istimewa! Hanya untuk masa yang terhad, nikmati muzik tanpa had dengan harga yang sangat berpatutan.",
|
||||||
|
date: "11:59 malam",
|
||||||
|
isRead: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
sender: "Ahmad Zulkifli",
|
||||||
|
subject: "Mesyuarat Projek Baru",
|
||||||
|
preview: "Sila hadir ke mesyuarat projek baru pada...",
|
||||||
|
content:
|
||||||
|
"Sila hadir ke mesyuarat projek baru pada hari Isnin, 10 Julai 2023, jam 10 pagi di Bilik Mesyuarat Utama. Kita akan membincangkan perancangan dan pembahagian tugas untuk projek baru ini.",
|
||||||
|
date: "10:21 malam",
|
||||||
|
isRead: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
sender: "Syarikat ABC",
|
||||||
|
subject: "Tawaran Kerja",
|
||||||
|
preview: "Kami dengan sukacitanya menawarkan anda jawatan...",
|
||||||
|
content:
|
||||||
|
"Kami dengan sukacitanya menawarkan anda jawatan Pengaturcara Kanan di Syarikat ABC. Sila baca lampiran untuk maklumat lanjut tentang tawaran ini dan hubungi kami jika anda mempunyai sebarang pertanyaan.",
|
||||||
|
date: "8:37 malam",
|
||||||
|
isRead: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
sender: "Puan Mariam",
|
||||||
|
subject: "Peringatan: Bayaran Bil",
|
||||||
|
preview: "Ini adalah peringatan untuk pembayaran bil anda...",
|
||||||
|
content:
|
||||||
|
"Ini adalah peringatan untuk pembayaran bil anda yang telah tamat tempoh. Sila jelaskan bayaran sebelum 30 Jun 2023 untuk mengelakkan sebarang caj lewat.",
|
||||||
|
date: "4:38 petang",
|
||||||
|
isRead: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const selectedMessages = ref([]);
|
||||||
|
const currentMessage = ref(null);
|
||||||
|
|
||||||
|
const selectMessage = (messageId) => {
|
||||||
|
const index = selectedMessages.value.indexOf(messageId);
|
||||||
|
if (index === -1) {
|
||||||
|
selectedMessages.value.push(messageId);
|
||||||
|
} else {
|
||||||
|
selectedMessages.value.splice(index, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteSelectedMessages = () => {
|
||||||
|
messages.value = messages.value.filter(
|
||||||
|
(message) => !selectedMessages.value.includes(message.id)
|
||||||
|
);
|
||||||
|
selectedMessages.value = [];
|
||||||
|
currentMessage.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const readMessage = (message) => {
|
||||||
|
currentMessage.value = message;
|
||||||
|
if (!message.isRead) {
|
||||||
|
message.isRead = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeMessage = () => {
|
||||||
|
currentMessage.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const addNewMessage = () => {
|
||||||
|
const newId = messages.value.length + 1;
|
||||||
|
const newMessage = {
|
||||||
|
id: newId,
|
||||||
|
sender: "New Sender",
|
||||||
|
subject: "New Subject",
|
||||||
|
preview: "This is a new message...",
|
||||||
|
content:
|
||||||
|
"This is the full content of the new message. You can edit this to add more details.",
|
||||||
|
date: new Date().toLocaleString(),
|
||||||
|
isRead: false,
|
||||||
|
};
|
||||||
|
messages.value.unshift(newMessage);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="bg-gray-100 min-h-screen">
|
||||||
|
<LayoutsBreadcrumb />
|
||||||
|
|
||||||
|
<div class="container mx-auto">
|
||||||
|
<rs-card>
|
||||||
|
<div class="flex items-center justify-between p-5">
|
||||||
|
<h2 class="text-xl font-semibold text-gray-800">Senarai Mesej</h2>
|
||||||
|
<div class="flex space-x-2">
|
||||||
|
<rs-button @click="addNewMessage" variant="success">
|
||||||
|
Tambah Mesej
|
||||||
|
</rs-button>
|
||||||
|
<rs-button
|
||||||
|
@click="deleteSelectedMessages"
|
||||||
|
variant="danger"
|
||||||
|
:disabled="selectedMessages.length === 0"
|
||||||
|
>
|
||||||
|
Buang ({{ selectedMessages.length }})
|
||||||
|
</rs-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="divide-y divide-gray-200">
|
||||||
|
<div
|
||||||
|
v-for="message in messages"
|
||||||
|
:key="message.id"
|
||||||
|
@click="readMessage(message)"
|
||||||
|
class="flex items-center p-4 hover:bg-gray-50 transition duration-150 ease-in-out cursor-pointer"
|
||||||
|
:class="{ 'bg-blue-50': selectedMessages.includes(message.id) }"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:checked="selectedMessages.includes(message.id)"
|
||||||
|
@click.stop="selectMessage(message.id)"
|
||||||
|
class="mr-4 h-5 w-5 text-blue-600"
|
||||||
|
/>
|
||||||
|
<div class="flex-grow">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span
|
||||||
|
class="font-medium text-gray-900"
|
||||||
|
:class="{ 'font-bold': !message.isRead }"
|
||||||
|
>
|
||||||
|
{{ message.sender }}
|
||||||
|
</span>
|
||||||
|
<span class="text-sm text-gray-500">{{ message.date }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-1">
|
||||||
|
<span
|
||||||
|
class="text-sm font-medium text-gray-900"
|
||||||
|
:class="{ 'font-bold': !message.isRead }"
|
||||||
|
>
|
||||||
|
{{ message.subject }}
|
||||||
|
</span>
|
||||||
|
<span class="text-sm text-gray-600">
|
||||||
|
- {{ message.preview }}</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</rs-card>
|
||||||
|
|
||||||
|
<!-- Message Content Modal -->
|
||||||
|
<rs-modal v-model="currentMessage" title="Message Details">
|
||||||
|
<template v-if="currentMessage">
|
||||||
|
<p class="text-sm text-gray-600 mb-2">
|
||||||
|
From: {{ currentMessage.sender }}
|
||||||
|
</p>
|
||||||
|
<p class="text-sm text-gray-600 mb-4">
|
||||||
|
Date: {{ currentMessage.date }}
|
||||||
|
</p>
|
||||||
|
<div class="border-t pt-4">
|
||||||
|
<p class="text-gray-800">{{ currentMessage.content }}</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</rs-modal>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Add any additional styles here */
|
||||||
|
</style>
|
284
pages/tipografi/index.vue
Normal file
284
pages/tipografi/index.vue
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
<script setup>
|
||||||
|
definePageMeta({
|
||||||
|
title: "Tipografi",
|
||||||
|
breadcrumb: [
|
||||||
|
{
|
||||||
|
name: "Tipografi",
|
||||||
|
type: "current",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const showCode1 = ref(false);
|
||||||
|
const showCode2 = ref(false);
|
||||||
|
const showCode3 = ref(false);
|
||||||
|
const showCode4 = ref(false);
|
||||||
|
const tooltips = ref({});
|
||||||
|
|
||||||
|
const copyCode = (codeId) => {
|
||||||
|
const codeElement = document.getElementById(codeId);
|
||||||
|
if (codeElement) {
|
||||||
|
const codeText = codeElement.textContent;
|
||||||
|
navigator.clipboard.writeText(codeText).then(() => {
|
||||||
|
tooltips.value[codeId] = "Kod disalin!";
|
||||||
|
setTimeout(() => {
|
||||||
|
tooltips.value[codeId] = "";
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<LayoutsBreadcrumb />
|
||||||
|
|
||||||
|
<rs-card>
|
||||||
|
<template #header> Tipografi </template>
|
||||||
|
<template #body>
|
||||||
|
<p class="mb-4">
|
||||||
|
Dokumentasi tipografi untuk pembangun untuk melihat dan menggunakan.
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
</rs-card>
|
||||||
|
|
||||||
|
<!-- Tajuk -->
|
||||||
|
<rs-card>
|
||||||
|
<template #header> Tajuk </template>
|
||||||
|
<template #body>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<h1 class="text-4xl font-bold">Tajuk 1</h1>
|
||||||
|
<h2 class="text-3xl font-bold">Tajuk 2</h2>
|
||||||
|
<h3 class="text-2xl font-bold">Tajuk 3</h3>
|
||||||
|
<h4 class="text-xl font-bold">Tajuk 4</h4>
|
||||||
|
<h5 class="text-lg font-bold">Tajuk 5</h5>
|
||||||
|
<h6 class="text-base font-bold">Tajuk 6</h6>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end mt-2">
|
||||||
|
<button
|
||||||
|
class="text-sm border border-slate-200 py-1 px-3 rounded-lg"
|
||||||
|
@click="showCode1 ? (showCode1 = false) : (showCode1 = true)"
|
||||||
|
>
|
||||||
|
Tunjukkan Kod
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<ClientOnly>
|
||||||
|
<transition name="fade">
|
||||||
|
<div v-show="showCode1" v-highlight>
|
||||||
|
<div class="relative">
|
||||||
|
<button
|
||||||
|
@click="copyCode('code1')"
|
||||||
|
class="absolute top-4 right-2 text-sm bg-gray-300 hover:bg-gray-300 py-1 px-3 rounded z-10"
|
||||||
|
>
|
||||||
|
Salin Kod
|
||||||
|
</button>
|
||||||
|
<transition name="tooltip">
|
||||||
|
<span
|
||||||
|
v-if="tooltips['code1']"
|
||||||
|
class="absolute top-0 right-0 mt-12 mr-2 bg-black text-white text-xs rounded py-1 px-2 z-10"
|
||||||
|
>
|
||||||
|
{{ tooltips["code1"] }}
|
||||||
|
</span>
|
||||||
|
</transition>
|
||||||
|
<pre id="code1" class="language-html">
|
||||||
|
<code>
|
||||||
|
<h1 class="text-4xl font-bold">Tajuk 1</h1>
|
||||||
|
<h2 class="text-3xl font-bold">Tajuk 2</h2>
|
||||||
|
<h3 class="text-2xl font-bold">Tajuk 3</h3>
|
||||||
|
<h4 class="text-xl font-bold">Tajuk 4</h4>
|
||||||
|
<h5 class="text-lg font-bold">Tajuk 5</h5>
|
||||||
|
<h6 class="text-base font-bold">Tajuk 6</h6>
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</ClientOnly>
|
||||||
|
</template>
|
||||||
|
</rs-card>
|
||||||
|
|
||||||
|
<!-- Perenggan -->
|
||||||
|
<rs-card>
|
||||||
|
<template #header> Perenggan </template>
|
||||||
|
<template #body>
|
||||||
|
<p class="mb-2">
|
||||||
|
Ini adalah perenggan lalai. Ia menggunakan saiz fon asas dan
|
||||||
|
ketinggian baris.
|
||||||
|
</p>
|
||||||
|
<p class="text-sm mb-2">
|
||||||
|
Ini adalah perenggan kecil menggunakan kelas text-sm.
|
||||||
|
</p>
|
||||||
|
<p class="text-lg mb-2">
|
||||||
|
Ini adalah perenggan besar menggunakan kelas text-lg.
|
||||||
|
</p>
|
||||||
|
<p class="font-light mb-2">Ini adalah perenggan berat ringan.</p>
|
||||||
|
<p class="font-semibold mb-2">Ini adalah perenggan separa tebal.</p>
|
||||||
|
<div class="flex justify-end mt-2">
|
||||||
|
<button
|
||||||
|
class="text-sm border border-slate-200 py-1 px-3 rounded-lg"
|
||||||
|
@click="showCode2 ? (showCode2 = false) : (showCode2 = true)"
|
||||||
|
>
|
||||||
|
Tunjukkan Kod
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<ClientOnly>
|
||||||
|
<transition name="fade">
|
||||||
|
<div v-show="showCode2" v-highlight>
|
||||||
|
<div class="relative">
|
||||||
|
<button
|
||||||
|
@click="copyCode('code2')"
|
||||||
|
class="absolute top-4 right-2 text-sm bg-gray-300 hover:bg-gray-300 py-1 px-3 rounded z-10"
|
||||||
|
>
|
||||||
|
Salin Kod
|
||||||
|
</button>
|
||||||
|
<transition name="tooltip">
|
||||||
|
<span
|
||||||
|
v-if="tooltips['code2']"
|
||||||
|
class="absolute top-0 right-0 mt-12 mr-2 bg-black text-white text-xs rounded py-1 px-2 z-10"
|
||||||
|
>
|
||||||
|
{{ tooltips["code2"] }}
|
||||||
|
</span>
|
||||||
|
</transition>
|
||||||
|
<pre id="code2" class="language-html">
|
||||||
|
<code>
|
||||||
|
<p>Ini adalah perenggan lalai. Ia menggunakan saiz fon asas dan ketinggian baris.</p>
|
||||||
|
<p class="text-sm">Ini adalah perenggan kecil menggunakan kelas text-sm.</p>
|
||||||
|
<p class="text-lg">Ini adalah perenggan besar menggunakan kelas text-lg.</p>
|
||||||
|
<p class="font-light">Ini adalah perenggan berat ringan.</p>
|
||||||
|
<p class="font-semibold">Ini adalah perenggan separa tebal.</p>
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</ClientOnly>
|
||||||
|
</template>
|
||||||
|
</rs-card>
|
||||||
|
|
||||||
|
<!-- Warna Teks -->
|
||||||
|
<rs-card>
|
||||||
|
<template #header> Warna Teks </template>
|
||||||
|
<template #body>
|
||||||
|
<p class="text-primary mb-2">Ini adalah teks warna utama.</p>
|
||||||
|
<p class="text-secondary mb-2">Ini adalah teks warna sekunder.</p>
|
||||||
|
<p class="text-gray-500 mb-2">Ini adalah teks warna kelabu.</p>
|
||||||
|
<p class="text-red-500 mb-2">Ini adalah teks warna merah.</p>
|
||||||
|
<p class="text-green-500 mb-2">Ini adalah teks warna hijau.</p>
|
||||||
|
<div class="flex justify-end mt-2">
|
||||||
|
<button
|
||||||
|
class="text-sm border border-slate-200 py-1 px-3 rounded-lg"
|
||||||
|
@click="showCode3 ? (showCode3 = false) : (showCode3 = true)"
|
||||||
|
>
|
||||||
|
Tunjukkan Kod
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<ClientOnly>
|
||||||
|
<transition name="fade">
|
||||||
|
<div v-show="showCode3" v-highlight>
|
||||||
|
<div class="relative">
|
||||||
|
<button
|
||||||
|
@click="copyCode('code3')"
|
||||||
|
class="absolute top-4 right-2 text-sm bg-gray-300 hover:bg-gray-300 py-1 px-3 rounded z-10"
|
||||||
|
>
|
||||||
|
Salin Kod
|
||||||
|
</button>
|
||||||
|
<transition name="tooltip">
|
||||||
|
<span
|
||||||
|
v-if="tooltips['code3']"
|
||||||
|
class="absolute top-0 right-0 mt-12 mr-2 bg-black text-white text-xs rounded py-1 px-2 z-10"
|
||||||
|
>
|
||||||
|
{{ tooltips["code3"] }}
|
||||||
|
</span>
|
||||||
|
</transition>
|
||||||
|
<pre id="code3" class="language-html">
|
||||||
|
<code>
|
||||||
|
<p class="text-primary">Ini adalah teks warna utama.</p>
|
||||||
|
<p class="text-secondary">Ini adalah teks warna sekunder.</p>
|
||||||
|
<p class="text-gray-500">Ini adalah teks warna kelabu.</p>
|
||||||
|
<p class="text-red-500">Ini adalah teks warna merah.</p>
|
||||||
|
<p class="text-green-500">Ini adalah teks warna hijau.</p>
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</ClientOnly>
|
||||||
|
</template>
|
||||||
|
</rs-card>
|
||||||
|
|
||||||
|
<!-- Gaya Fon -->
|
||||||
|
<rs-card>
|
||||||
|
<template #header> Gaya Fon </template>
|
||||||
|
<template #body>
|
||||||
|
<p class="italic mb-2">Ini adalah teks condong.</p>
|
||||||
|
<p class="font-bold mb-2">Ini adalah teks tebal.</p>
|
||||||
|
<p class="underline mb-2">Ini adalah teks bergaris.</p>
|
||||||
|
<p class="line-through mb-2">Ini adalah teks dicoret.</p>
|
||||||
|
<p class="uppercase mb-2">Ini adalah teks huruf besar.</p>
|
||||||
|
<p class="lowercase mb-2">Ini adalah teks huruf kecil.</p>
|
||||||
|
<p class="capitalize mb-2">Ini adalah teks huruf awal besar.</p>
|
||||||
|
<div class="flex justify-end mt-2">
|
||||||
|
<button
|
||||||
|
class="text-sm border border-slate-200 py-1 px-3 rounded-lg"
|
||||||
|
@click="showCode4 ? (showCode4 = false) : (showCode4 = true)"
|
||||||
|
>
|
||||||
|
Tunjukkan Kod
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<ClientOnly>
|
||||||
|
<transition name="fade">
|
||||||
|
<div v-show="showCode4" v-highlight>
|
||||||
|
<div class="relative">
|
||||||
|
<button
|
||||||
|
@click="copyCode('code4')"
|
||||||
|
class="absolute top-4 right-2 text-sm bg-gray-300 hover:bg-gray-300 py-1 px-3 rounded z-10"
|
||||||
|
>
|
||||||
|
Salin Kod
|
||||||
|
</button>
|
||||||
|
<transition name="tooltip">
|
||||||
|
<span
|
||||||
|
v-if="tooltips['code4']"
|
||||||
|
class="absolute top-0 right-0 mt-12 mr-2 bg-black text-white text-xs rounded py-1 px-2 z-10"
|
||||||
|
>
|
||||||
|
{{ tooltips["code4"] }}
|
||||||
|
</span>
|
||||||
|
</transition>
|
||||||
|
<pre id="code4" class="language-html">
|
||||||
|
<code>
|
||||||
|
<p class="italic">Ini adalah teks condong.</p>
|
||||||
|
<p class="font-bold">Ini adalah teks tebal.</p>
|
||||||
|
<p class="underline">Ini adalah teks bergaris.</p>
|
||||||
|
<p class="line-through">Ini adalah teks dicoret.</p>
|
||||||
|
<p class="uppercase">Ini adalah teks huruf besar.</p>
|
||||||
|
<p class="lowercase">Ini adalah teks huruf kecil.</p>
|
||||||
|
<p class="capitalize">Ini adalah teks huruf awal besar.</p>
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</ClientOnly>
|
||||||
|
</template>
|
||||||
|
</rs-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.5s;
|
||||||
|
}
|
||||||
|
.fade-enter,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-enter-active,
|
||||||
|
.tooltip-leave-active {
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
|
.tooltip-enter,
|
||||||
|
.tooltip-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
Binary file not shown.
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 3.8 KiB |
Loading…
x
Reference in New Issue
Block a user