Merge branch 'dev-bagus' of github.com:defuj/eis into dev-bagus

This commit is contained in:
kur0nek-o 2024-03-18 09:24:12 +07:00
commit aa2e8114b8
317 changed files with 679525 additions and 20909 deletions

2
.dockerignore Normal file
View File

@ -0,0 +1,2 @@
node_modules
npm-debug.log

4
.env.development Normal file → Executable file
View File

@ -1,4 +1,6 @@
VITE_BASE_URL=http://localhost:5173
VITE_BASE_DIRECTORY=/
VITE_APP_VERSION=0.0.1
VITE_APP_NAME='Executive Information System'
VITE_APP_NAME='Executive Information System'
VITE_APP_GRAPHQL_ENDPOINT=http://192.168.191.163:32169/graphql
VITE_APP_REST_ENDPOINT=http://192.168.191.163:32180

4
.env.production Normal file → Executable file
View File

@ -1,4 +1,6 @@
VITE_BASE_URL=https://api.domain.com/v1/
VITE_BASE_DIRECTORY=/
VITE_APP_VERSION=0.0.1
VITE_APP_NAME='Executive Information System'
VITE_APP_NAME='Executive Information System'
VITE_APP_GRAPHQL_ENDPOINT=http://10.1.50.173:32180/graphql
VITE_APP_REST_ENDPOINT=http://10.1.50.173:32181

0
.eslintrc.cjs Normal file → Executable file
View File

23
.github/workflows/docker-image-development.yml vendored Normal file → Executable file
View File

@ -2,27 +2,24 @@ name: Publish Docker Image Development
on:
push:
branches: [ "development" ]
branches: ['development']
pull_request:
branches: [ "development" ]
branches: ['development']
jobs:
build:
runs-on: ubuntu-latest
if: ${{github.event.head_commit.message}} == *'build image'*
steps:
- name: Docker Hub Login
env:
- name: Docker Hub Login
env:
DOCKER_USERNAME: ${{secrets.DOCKER_USERNAME}}
DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}}
run: docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
run: docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
- uses: actions/checkout@v3
- name: Build the Docker image
run: |
docker build . -t defuj/apkt-eis:v1.0.0-dev
docker push defuj/apkt-eis:v1.0.0-dev
- uses: actions/checkout@v3
- name: Build the Docker image
run: |
docker build . --file Dockerfile --tag defuj/apkt-eis:v0.0.10-vm
docker push defuj/apkt-eis:v0.0.10-vm

View File

@ -23,8 +23,7 @@ jobs:
- name: Build the Docker image
run: |
docker build . -t defuj/apkt-eis
docker image tag defuj/apkt-eis defuj/apkt-eis:v1.0.1-release
docker build . --file Dockerfile --tag defuj/apkt-eis:v1.0.1-release
docker push defuj/apkt-eis:v1.0.1-release

1
.gitignore vendored Normal file → Executable file
View File

@ -11,6 +11,7 @@ lerna-debug.log*
node_modules
.DS_Store
dist
build
dist-ssr
coverage
*.local

0
.prettierrc.json Normal file → Executable file
View File

View File

@ -1,553 +0,0 @@
[
"-left-2",
"-mr-1",
"-mr-12",
"-translate-x-full",
"-translate-y-2/4",
"2xl:text-sm",
"absolute",
"animate-spin",
"auto-cols-auto",
"backdrop-blur",
"bg-black",
"bg-gray-100",
"bg-gray-200",
"bg-gray-50",
"bg-gray-500",
"bg-gray-600",
"bg-gray-900",
"bg-indigo-600",
"bg-layout",
"bg-none",
"bg-opacity-100",
"bg-opacity-25",
"bg-opacity-5",
"bg-opacity-60",
"bg-opacity-75",
"bg-opacity-80",
"bg-primary-100",
"bg-primary-400",
"bg-primary-50",
"bg-primary-500",
"bg-red-100",
"bg-red-600",
"bg-secondary-100",
"bg-teal-600",
"bg-vtd-primary-100",
"bg-vtd-primary-500",
"bg-vtd-primary-600",
"bg-white",
"bg-yellow-100",
"bg-yellow-600",
"block",
"blur",
"border",
"border-0",
"border-b",
"border-b-0",
"border-black/[.1]",
"border-gray-300",
"border-gray-600",
"border-none",
"border-primary-500",
"border-r",
"border-solid",
"border-t",
"border-transparent",
"bottom-0",
"col-span-7",
"cursor-default",
"cursor-pointer",
"dark:bg-opacity-50",
"dark:focus:bg-opacity-50",
"dark:focus:border-vtd-primary-500",
"dark:focus:ring-opacity-20",
"dark:focus:ring-opacity-25",
"dark:focus:text-vtd-primary-300",
"dark:hover:text-vtd-primary-300",
"dark:text-opacity-70",
"dark:text-vtd-primary-400",
"delay-300",
"disabled:bg-primary-200",
"disabled:bg-primary-300",
"disabled:bg-primary-400",
"disabled:border-primary-300",
"disabled:cursor-not-allowed",
"disabled:text-primary-300",
"disabled:text-primary-400",
"divide-gray-500",
"divide-opacity-10",
"divide-y",
"duration-100",
"duration-150",
"duration-200",
"duration-300",
"duration-500",
"duration-75",
"ease-in",
"ease-in-out",
"ease-linear",
"ease-out",
"fill-gray-500",
"fill-gray-600",
"fill-green-600",
"fill-primary-300",
"fill-primary-500",
"fill-red-600",
"fill-white",
"filter",
"fixed",
"flex",
"flex-1",
"flex-col",
"flex-grow",
"flex-none",
"flex-row",
"flex-shrink-0",
"flex-wrap",
"focus-visible:outline",
"focus-visible:outline-2",
"focus-visible:outline-indigo-600",
"focus-visible:outline-offset-2",
"focus-visible:ring-2",
"focus-visible:ring-offset-2",
"focus-visible:ring-offset-teal-300",
"focus-visible:ring-opacity-75",
"focus-visible:ring-white",
"focus:bg-vtd-primary-50",
"focus:border-0",
"focus:border-vtd-primary-300",
"focus:outline-0",
"focus:outline-none",
"focus:ring",
"focus:ring-0",
"focus:ring-2",
"focus:ring-indigo-500",
"focus:ring-inset",
"focus:ring-offset-0",
"focus:ring-offset-2",
"focus:ring-opacity-10",
"focus:ring-primary-500",
"focus:ring-vtd-primary-500",
"focus:ring-white",
"focus:text-gray-500",
"focus:text-vtd-primary-600",
"font-bold",
"font-light",
"font-medium",
"font-normal",
"font-semibold",
"gap-1",
"gap-3",
"gap-x-1",
"gap-x-1.5",
"gap-x-2",
"gap-x-6",
"gap-y-0",
"gap-y-0.5",
"gap-y-1",
"grid",
"grid-cols-2",
"grid-cols-7",
"grid-flow-col",
"group-hover:bg-opacity-80",
"group-hover:bg-primary-500",
"group-hover:block",
"group-hover:fill-primary-500",
"group-hover:fill-white",
"group-hover:text-gray-500",
"group-hover:text-primary-500",
"group-hover:text-white",
"grow",
"h-0",
"h-10",
"h-11",
"h-12",
"h-16",
"h-4",
"h-5",
"h-6",
"h-7",
"h-8",
"h-9",
"h-[2.7rem]",
"h-[56px]",
"h-[66px]",
"h-[calc(100%-64px)]",
"h-[calc(90vh-24px)]",
"h-fit",
"h-full",
"h-screen-80",
"hidden",
"hover:bg-gray-50",
"hover:bg-indigo-500",
"hover:bg-indigo-700",
"hover:bg-primary-100",
"hover:bg-primary-200",
"hover:bg-primary-600",
"hover:bg-red-500",
"hover:bg-vtd-primary-700",
"hover:bg-yellow-500",
"hover:border-primary-500",
"hover:text-primary-500",
"hover:text-vtd-primary-700",
"inline-block",
"inline-flex",
"inset-0",
"inset-y-0",
"italic",
"items-center",
"items-start",
"justify-between",
"justify-center",
"justify-end",
"justify-start",
"leading-5",
"leading-6",
"leading-7",
"leading-none",
"leading-relaxed",
"left-0",
"left-4",
"left-auto",
"lg:block",
"lg:border-b-0",
"lg:border-r",
"lg:flex-nowrap",
"lg:grid-cols-3",
"lg:h-10",
"lg:mb-0",
"lg:mr-1",
"lg:mt-12",
"lg:mt-6",
"lg:mx-0",
"lg:px-8",
"lg:text-xs",
"lg:w-10",
"lg:w-80",
"line-clamp-1",
"max-h-0",
"max-h-60",
"max-h-[1000px]",
"max-h-[calc(100vh-140px)]",
"max-w-2xl",
"max-w-7xl",
"max-w-sm",
"max-w-xs",
"mb-2",
"mb-3",
"mb-4",
"mb-6",
"mb-8",
"md:bg-primary-500",
"md:block",
"md:fixed",
"md:flex",
"md:flex-col",
"md:h-16",
"md:hidden",
"md:inset-y-0",
"md:ml-6",
"md:ml-80",
"md:mr-3",
"md:mr-6",
"md:mt-8",
"md:p-20",
"md:pl-4",
"md:pl-80",
"md:px-6",
"md:py-0",
"md:rounded-t-3xl",
"md:text-2xl",
"md:text-3xl",
"md:w-1/2",
"md:w-80",
"md:w-[300px]",
"md:w-[440px]",
"me-1",
"min-h-full",
"min-h-screen",
"ml-1",
"ml-2",
"ml-3",
"ml-4",
"mr-1",
"mr-2",
"mt-0",
"mt-0.5",
"mt-1",
"mt-1.5",
"mt-10",
"mt-2",
"mt-3",
"mt-3.5",
"mt-4",
"mt-5",
"mt-6",
"mx-2",
"mx-3",
"mx-auto",
"my-1",
"my-auto",
"object-contain",
"opacity-0",
"opacity-100",
"opacity-25",
"opacity-30",
"opacity-40",
"opacity-50",
"opacity-75",
"order-last",
"ordinal",
"origin-top-left",
"outline",
"outline-0",
"overflow-auto",
"overflow-hidden",
"overflow-y-auto",
"p-1",
"p-1.5",
"p-2",
"p-4",
"pb-4",
"peer-checked:text-primary-500",
"pl-1",
"pl-10",
"pl-11",
"pl-2",
"pl-3",
"place-items-center",
"placeholder-gray-500",
"placeholder:text-gray-400",
"placeholder:text-sm",
"pointer-events-auto",
"pointer-events-none",
"pr-10",
"pr-12",
"pr-2",
"pr-4",
"pr-5",
"pr-7",
"pt-0",
"pt-0.5",
"pt-2",
"pt-5",
"px-0",
"px-0.5",
"px-1",
"px-1.5",
"px-2",
"px-3",
"px-3.5",
"px-4",
"px-6",
"py-0",
"py-1",
"py-1.5",
"py-14",
"py-2",
"py-2.5",
"py-24",
"py-3",
"py-4",
"py-6",
"relative",
"right-0",
"right-auto",
"ring-0",
"ring-1",
"ring-black",
"ring-gray-300",
"ring-inset",
"ring-opacity-5",
"rotate-180",
"rounded",
"rounded-2xl",
"rounded-b-2xl",
"rounded-full",
"rounded-l-full",
"rounded-lg",
"rounded-md",
"rounded-r-full",
"rounded-t-2xl",
"rounded-xl",
"scale-100",
"scale-95",
"scroll-py-2",
"select-none",
"shadow",
"shadow-2xl",
"shadow-gray-50",
"shadow-lg",
"shadow-md",
"shadow-sm",
"shadow-xl",
"shrink",
"sm:border",
"sm:border-b",
"sm:border-t-0",
"sm:col-start-1",
"sm:col-start-2",
"sm:flex",
"sm:flex-1",
"sm:flex-nowrap",
"sm:flex-row-reverse",
"sm:font-medium",
"sm:gap-3",
"sm:grid",
"sm:grid-cols-2",
"sm:grid-cols-3",
"sm:grid-flow-row-dense",
"sm:h-10",
"sm:hidden",
"sm:items-center",
"sm:items-start",
"sm:justify-between",
"sm:justify-start",
"sm:leading-4",
"sm:max-w-lg",
"sm:max-w-sm",
"sm:mb-0",
"sm:mb-1",
"sm:mb-1.5",
"sm:ml-2",
"sm:ml-3",
"sm:ml-4",
"sm:mr-2",
"sm:mt-0",
"sm:mt-1",
"sm:mt-2",
"sm:mt-2.5",
"sm:mt-4",
"sm:mt-5",
"sm:mt-6",
"sm:mx-0",
"sm:mx-1",
"sm:my-8",
"sm:order-none",
"sm:overflow-visible",
"sm:p-0",
"sm:p-6",
"sm:pb-4",
"sm:pr-6",
"sm:px-14",
"sm:px-2",
"sm:px-3",
"sm:px-4",
"sm:py-32",
"sm:py-4",
"sm:relative",
"sm:rounded-lg",
"sm:scale-100",
"sm:scale-95",
"sm:shadow-sm",
"sm:space-x-10",
"sm:space-x-4",
"sm:space-x-5",
"sm:space-x-reverse",
"sm:space-y-0",
"sm:static",
"sm:text-5xl",
"sm:text-left",
"sm:text-sm",
"sm:translate-y-0",
"sm:w-10",
"sm:w-auto",
"sm:w-full",
"sm:z-auto",
"space-x-1",
"space-x-1.5",
"space-y-1",
"space-y-2",
"space-y-3",
"space-y-4",
"sr-only",
"static",
"sticky",
"stroke-white",
"text-2xl",
"text-3xl",
"text-[8px]",
"text-aside",
"text-base",
"text-blue-400",
"text-center",
"text-dark",
"text-gray-200",
"text-gray-300",
"text-gray-400",
"text-gray-500",
"text-gray-600",
"text-gray-700",
"text-gray-800",
"text-gray-900",
"text-green-400",
"text-green-600",
"text-indigo-600",
"text-left",
"text-lg",
"text-opacity-40",
"text-orange-400",
"text-orange-600",
"text-primary-50",
"text-primary-500",
"text-primary-800",
"text-red-400",
"text-red-600",
"text-slate-600",
"text-slate-900",
"text-sm",
"text-start",
"text-teal-600",
"text-vtd-primary-500",
"text-vtd-primary-600",
"text-white",
"text-xl",
"text-xs",
"text-yellow-700",
"top-0",
"top-1/2",
"top-3",
"top-3.5",
"top-full",
"tracking-tight",
"tracking-wide",
"transform",
"transition",
"transition-all",
"transition-colors",
"transition-opacity",
"transition-transform",
"translate-x-0",
"translate-x-4",
"translate-y-0",
"translate-y-3",
"translate-y-4",
"truncate",
"uppercase",
"visible",
"w-0",
"w-1/2",
"w-10",
"w-12",
"w-14",
"w-16",
"w-4",
"w-5",
"w-56",
"w-6",
"w-8",
"w-80",
"w-9",
"w-[170px]",
"w-[2.7rem]",
"w-[266px]",
"w-auto",
"w-full",
"whitespace-nowrap",
"whitespace-pre-wrap",
"z-10",
"z-20",
"z-40",
"z-50"
]

0
.vscode/extensions.json vendored Normal file → Executable file
View File

29
Dockerfile Normal file → Executable file
View File

@ -1,13 +1,20 @@
FROM node:lts-alpine as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# syntax=docker/dockerfile:1
# build stage
# FROM node:lts-alpine as builder
# WORKDIR /apkt
# COPY package*.json ./
# RUN npm install && npm install npm-run-all -g
# COPY . .
# RUN npm run build
# # production stage
# FROM nginx:stable-alpine
# COPY --from=builder /apkt/dist /usr/share/nginx/html
# COPY --from=builder /apkt/nginx.conf /etc/nginx/nginx.conf
# EXPOSE 32166
# CMD ["nginx", "-g", "daemon off;"]
# tahap produksi
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
COPY --from=build-stage /app/nginx.conf /etc/nginx/nginx.conf
FROM nginx:stable-alpine
COPY /dist /usr/share/nginx/html
COPY /nginx.conf /etc/nginx/nginx.conf
EXPOSE 32166
CMD ["nginx", "-g", "daemon off;"]
CMD ["nginx", "-g", "daemon off;"]

76
README.md Normal file → Executable file
View File

@ -1,52 +1,26 @@
# Executive Information System
# TABLE MENU DOCUMENTATION
## Monalisa
### Gangguan > Rekapitulasi
| CODE | MENU | FILE |
| ------- | ---------------------------------------- | ------------ |
| MON0001 | Jumlah Kali Gangguan | Table_36.vue |
| MON0002 | Dispacthing Time (DT) Gangguan | Table_37.vue |
| MON0003 | Recovery Time (RCT) Gangguan | Table_38.vue |
| MON0004 | Response Time (RPT) Gangguan | Table_39.vue |
| MON0005 | Jumlah dan Durasi RPT RCT Gangguan | Table_40.vue |
| MON0006 | Rekapitulasi Gangguan Per Jenis Gangguan | Table_41.vue |
| MON0007 | Rekapitulasi Lapor Ulang Gangguan | Table_42.vue |
| MON0008 | Rekapitulasi ENS Gangguan | Table_43.vue |
| MON0009 | Rekapitulasi Gangguan Belum Selesai | Table_44.vue |
| MON0010 | Jumlah Kali Keluhan | Table_45.vue |
| MON0011 | Recovery Time (RCT) Keluhan | Table_46.vue |
| MON0012 | Response Time (RPT) Keluhan | Table_47.vue |
| MON0013 | Jumlah dan Durasi RPT RCT Keluhan | Table_48.vue |
| MON0014 | Rekapitulasi Gangguan Per Jenis Keluhan | Table_49.vue |
| MON0015 | Rekapitulasi Lapor Ulang Keluhan | Table_50.vue |
| MON0016 | Rekapitulasi Gangguan Belum Selesai | Table_51.vue |
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
1. Disable the built-in TypeScript Extension
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
```sh
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Type-Check, Compile and Minify for Production
```sh
npm run build
```
### Run Unit Tests with [Vitest](https://vitest.dev/)
```sh
npm run test:unit
```
### Lint with [ESLint](https://eslint.org/)
```sh
npm run lint
```
### Keluhan > Rekapitulasi
| CODE | MENU | FILE |
| ------- | ------------------- | ------------ |
| MON0010 | Jumlah Kali Keluhan | Table_45.vue |

View File

@ -1,22 +1,22 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: apkt-eis
name: apkt-eis
spec:
replicas: 3
selector:
matchLabels:
app: apkt-eis
template:
metadata:
labels:
app: apkt-eis
spec:
containers:
- name: apkt-eis
image: defuj/apkt-eis:v1.0.1-dev
ports:
- containerPort: 80
replicas: 3
selector:
matchLabels:
app: apkt-eis
template:
metadata:
labels:
app: apkt-eis
spec:
containers:
- name: apkt-eis
image: defuj/apkt-eis:v0.0.10-vm
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
@ -43,4 +43,4 @@ spec:
- protocol: TCP
port: 32166
targetPort: 80
type: ClusterIP
type: ClusterIP

0
env.d.ts vendored Normal file → Executable file
View File

0
index.html Normal file → Executable file
View File

0
nginx.conf Normal file → Executable file
View File

13335
package-lock.json generated Normal file → Executable file

File diff suppressed because it is too large Load Diff

41
package.json Normal file → Executable file
View File

@ -11,31 +11,37 @@
"build-only": "vite build",
"type-check": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/",
"prepare": "tw-patch install"
"format": "prettier --write src/"
},
"dependencies": {
"@apollo/client": "^3.8.8",
"@apollo/client": "^3.8.10",
"@apollo/link-context": "^2.0.0-beta.3",
"@flavorly/vanilla-components": "^0.7.65",
"@headlessui/tailwindcss": "^0.2.0",
"@headlessui/vue": "^1.7.16",
"@headlessui/vue": "^1.7.19",
"@heroicons/vue": "^2.0.18",
"@lottiefiles/lottie-player": "^2.0.2",
"@lottiefiles/lottie-player": "^2.0.4",
"@phosphor-icons/vue": "^2.1.6",
"@types/qs": "^6.9.9",
"@types/uuid": "^9.0.2",
"@vue/apollo-option": "^4.0.0-beta.12",
"devextreme": "23.1.5",
"devextreme-vue": "23.1.5",
"@types/qs": "^6.9.12",
"@types/uuid": "^9.0.8",
"@types/vue-select": "^3.16.8",
"@vue/apollo-components": "^4.0.0",
"@vue/apollo-composable": "^4.0.1",
"@vue/apollo-option": "^4.0.0",
"axios": "^1.6.7",
"devextreme": "23.2.4",
"devextreme-vue": "23.2.4",
"dotenv": "^16.3.1",
"encrypt-storage": "^2.12.16",
"encrypt-storage": "^2.12.22",
"exceljs": "^4.4.0",
"file-saver": "^2.0.5",
"graphql": "^16.8.1",
"graphql-tag": "^2.12.6",
"jspdf": "^2.5.1",
"jspdf-autotable": "^3.8.2",
"pinia": "^2.1.3",
"qs": "^6.11.2",
"uuid": "^9.0.0",
"uuid": "^9.0.1",
"vue": "^3.3.4",
"vue-router": "^4.2.2",
"vue-tailwind-datepicker": "^1.6.1"
@ -44,7 +50,7 @@
"@rushstack/eslint-patch": "^1.5.1",
"@tailwindcss/aspect-ratio": "^0.4.2",
"@tailwindcss/container-queries": "^0.1.1",
"@tailwindcss/forms": "^0.5.6",
"@tailwindcss/forms": "^0.5.7",
"@tailwindcss/typography": "^0.5.10",
"@tsconfig/node18": "^2.0.1",
"@types/file-saver": "^2.0.6",
@ -60,15 +66,12 @@
"eslint": "^8.39.0",
"eslint-plugin-vue": "^9.11.0",
"jsdom": "^22.1.0",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.24",
"prettier": "^3.0.3",
"tailwindcss": "^3.3.2",
"tailwindcss-patch": "^2.2.2",
"typescript": "~5.2.2",
"unplugin-tailwindcss-mangle": "^2.2.2",
"vite": "^4.3.9",
"vitest": "^0.34.6",
"vue-tsc": "^1.6.5"
"vitest": "^1.3.1",
"vue-tsc": "^2.0.5"
}
}
}

0
postcss.config.js Normal file → Executable file
View File

0
public/assets/css/loader.css Normal file → Executable file
View File

0
public/assets/images/favicon.ico Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

0
public/assets/images/pln.ico Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

0
src/App.vue Normal file → Executable file
View File

0
src/assets/css/base.css Normal file → Executable file
View File

View File

@ -0,0 +1,46 @@
.dx-datagrid-total-footer{
background-color: #035b71 !important;
}
.dx-datagrid-total-footer .dx-row.dx-footer-row{
background-color: #035b71 !important;
}
.dx-datagrid-total-footer > td{
background-color: #035b71 !important;
}
.dx-row.dx-datagrid-group-footer > td{
background-color: #e6eff1 !important;
}
.dx-datagrid-rowsview .dx-row.dx-group-row {
background-color: #F7F7F7 !important;
}
.dx-datagrid-group-footer{
background-color: #e6eff1 !important;
}
.dx-pager .dx-page-sizes .dx-selection, .dx-pager .dx-pages .dx-selection{
background-color: #035b71 !important;
}
.dx-datagrid-headers .dx-datagrid-table .dx-row > td{
font-size: 12px !important;
}
.dx-datagrid .dx-row > td{
font-size: 12px !important;
}
.dx-toolbar .dx-toolbar-items-container{
height: 56px !important;
}
.dx-texteditor-input{
border: 1px solid #d1d5db !important;
border-radius: 8px !important;
}
.dx-texteditor.dx-editor-filled::after{
border: none !important;
}
.dx-texteditor.dx-state-active::before, .dx-texteditor.dx-state-focused::before{
border: none !important;
}
.dx-button-has-icon .dx-icon{
font-size: 24px !important;
}
.dx-list-item-icon{
font-size: 24px !important;
}

23
src/assets/css/main.css Normal file → Executable file
View File

@ -2,25 +2,4 @@
@import 'devextreme/dist/css/dx.material.blue.light.compact.css';
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;700&display=swap');
@import './style.css';
.dx-datagrid-total-footer{
background-color: #035b71 !important;
}
.dx-datagrid-total-footer .dx-row.dx-footer-row{
background-color: #035b71 !important;
}
.dx-datagrid-total-footer > td{
background-color: #035b71 !important;
}
.dx-row.dx-datagrid-group-footer > td{
background-color: #e6eff1 !important;
}
.dx-datagrid-rowsview .dx-row.dx-group-row {
background-color: #F7F7F7 !important;
}
.dx-datagrid-group-footer{
background-color: #e6eff1 !important;
}
.dx-pager .dx-page-sizes .dx-selection, .dx-pager .dx-pages .dx-selection{
background-color: #035b71 !important;
}
@import './devextreme.custom.css';

3035
src/assets/css/style.css Normal file → Executable file

File diff suppressed because it is too large Load Diff

18
src/assets/css/tailwind.css Normal file → Executable file
View File

@ -26,8 +26,11 @@
@apply flex-shrink-0 block px-4 py-2 border-b bg-primary-500 border-gray-50;
}
/* Aside */
.aside-text{
@apply text-xs;
}
.aside-single-item {
@apply w-full flex items-center pl-2 pr-4 py-2 text-xs rounded-xl;
@apply aside-text w-full flex items-center pl-2 pr-4 py-2 rounded-xl;
}
.aside-single-item-active {
@apply aside-single-item bg-primary-500 text-white font-bold;
@ -47,4 +50,17 @@
.custom-table-column {
@apply !align-middle text-sm font-medium text-primary-800;
}
.filter-input-label {
@apply block mb-2 text-xs font-semibold text-gray-800 sm:mb-0;
}
.rich-select-trigger{
@apply bg-gray-200 border-none focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-teal-300 relative flex items-center justify-between w-full focus:z-10 cursor-pointer text-sm transition duration-100 ease-in-out disabled:opacity-50 disabled:cursor-not-allowed px-4 py-2.5;
}
.rich-select-search-input{
@apply inline-block focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-teal-300 w-full text-sm px-4 py-2.5 text-gray-700 placeholder-gray-500/60 border-0 rounded-lg bg-gray-200;
}
.rich-select-selected-highlighted-option{
@apply font-semibold bg-teal-600 focus:outline-none text-white;
}
}

0
src/assets/icons/dot-outline.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

0
src/assets/icons/gauge.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

0
src/assets/icons/lightning-slash.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

0
src/assets/icons/monitor.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

0
src/assets/icons/plugs.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

0
src/assets/icons/smiley-sad.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

0
src/assets/icons/swap.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

0
src/assets/images/hero.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

0
src/assets/images/pln-with-text.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

0
src/assets/images/pln.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -6,10 +6,6 @@ const props = defineProps({
type: String as () => 'button' | 'submit' | 'reset',
default: 'button'
},
onClick: {
type: Function as unknown as () => (payload: MouseEvent) => void,
default: () => {}
},
label: {
type: String,
default: ''
@ -47,12 +43,15 @@ const buttonStyle = computed(() => {
return 'bg-none text-primary-500 border border-transparent hover:border-primary-500 rounded-lg disabled:border-primary-300 disabled:text-primary-300'
}
})
const emit = defineEmits(['on:click'])
</script>
<template>
<button
:type="type"
@click="onClick"
@click="emit('on:click')"
:disabled="isLoading ? true : disabled"
:class="['px-3 py-2 text-sm font-semibold', buttonStyle, className]"
>

0
src/components/Buttons/ButtonDropdown.vue Normal file → Executable file
View File

1
src/components/Buttons/ButtonPrimary.vue Normal file → Executable file
View File

@ -1,4 +1,5 @@
<script setup lang="ts">
import * as LottiePlayer from "@lottiefiles/lottie-player";
defineProps({
type: {
type: String as () => "button" | "submit" | "reset",

82
src/components/CommandPalettes.vue Normal file → Executable file
View File

@ -80,48 +80,50 @@
<ul class="text-sm text-gray-700">
<ComboboxOption as="template" v-for="menu in query === '' ? recent : filteredMenus"
:key="menu.path" v-slot="{ active }">
<li @click="command.openMenu(menu)"
:class="['flex flex-row cursor-pointer select-none items-center rounded-md px-3 py-2', active && 'bg-primary-500 text-white']">
<component v-if="menu.path.includes('/gangguan/')" :is="navigationIcon[0]"
alt="icon"
:class="['h-6 w-6 flex-none', active ? 'fill-white' : 'fill-gray-600']" />
<component v-else-if="menu.path.includes('/keluhan/')"
:is="navigationIcon[1]" alt="icon"
:class="['h-6 w-6 flex-none', active ? 'fill-white' : 'fill-gray-600']" />
<component v-else-if="menu.path.includes('/monalisa/')"
:is="navigationIcon[2]" alt="icon"
:class="['h-6 w-6 flex-none', active ? 'fill-white' : 'fill-gray-600']" />
<component v-else-if="menu.path.includes('/check-in-out/')"
:is="navigationIcon[3]" alt="icon"
:class="['h-6 w-6 flex-none', active ? 'fill-white' : 'fill-gray-600']" />
<component v-else-if="menu.path.includes('/anomali-pengaduan/')"
:is="navigationIcon[4]" alt="icon"
:class="['h-6 w-6 flex-none', active ? 'fill-white' : 'fill-gray-600']" />
<component v-else-if="menu.path.includes('/ctt-kwh-periksa/')"
:is="navigationIcon[5]" alt="icon"
:class="['h-6 w-6 flex-none', active ? 'fill-white' : 'fill-gray-600']" />
<component v-else-if="menu.path.includes('/material/')"
:is="navigationIcon[6]" alt="icon"
:class="['h-6 w-6 flex-none', active ? 'fill-white' : 'fill-gray-600']" />
<component v-else-if="menu.path.includes('/transaksi/')"
:is="navigationIcon[7]" alt="icon"
:class="['h-6 w-6 flex-none', active ? 'fill-white' : 'fill-gray-600']" />
<component v-else :is="navigationIcon[8]" alt="icon"
:class="['h-6 w-6 flex-none', active ? 'fill-white' : 'fill-gray-600']" />
<li @click="command.openMenu(menu)" class="group">
<div class="flex flex-row items-center justify-between px-3 py-2 rounded-md cursor-pointer select-none lex group-hover:bg-primary-500 group-hover:text-white group-hover:bg-opacity-80">
<component v-if="menu.path.includes('/gangguan/')" :is="navigationIcon[0]"
alt="icon"
:class="['w-8 h-8 fill-gray-600 group-hover:fill-white flex']" />
<component v-else-if="menu.path.includes('/keluhan/')"
:is="navigationIcon[1]" alt="icon"
:class="['w-8 h-8 fill-gray-600 group-hover:fill-white flex']" />
<component v-else-if="menu.path.includes('/monalisa/')"
:is="navigationIcon[2]" alt="icon"
:class="['w-8 h-8 fill-gray-600 group-hover:fill-white flex']" />
<component v-else-if="menu.path.includes('/check-in-out/')"
:is="navigationIcon[3]" alt="icon"
:class="['w-8 h-8 fill-gray-600 group-hover:fill-white flex']" />
<component v-else-if="menu.path.includes('/anomali-pengaduan/')"
:is="navigationIcon[4]" alt="icon"
:class="['w-8 h-8 fill-gray-600 group-hover:fill-white flex']" />
<component v-else-if="menu.path.includes('/ctt-kwh-periksa/')"
:is="navigationIcon[5]" alt="icon"
:class="['w-8 h-8 fill-gray-600 group-hover:fill-white flex']" />
<component v-else-if="menu.path.includes('/material/')"
:is="navigationIcon[6]" alt="icon"
:class="['w-8 h-8 fill-gray-600 group-hover:fill-white flex']" />
<component v-else-if="menu.path.includes('/transaksi/')"
:is="navigationIcon[7]" alt="icon"
:class="['w-8 h-8 fill-gray-600 group-hover:fill-white flex']" />
<component v-else :is="navigationIcon[8]" alt="icon"
:class="['w-8 h-8 fill-gray-600 group-hover:fill-white flex']" />
<div class="flex flex-col flex-1 ml-3 space-y-1">
<span
:class="[active ? 'text-white' : 'text-gray-800', 'text-sm font-medium line-clamp-1']">
{{ menu.name }}
</span>
<span
:class="[active ? 'text-white' : 'text-gray-500', 'text-xs line-clamp-1']">
{{ menu.path.replace('/home/', '') }}
<div class="flex flex-col flex-1 ml-3 space-y-1">
<span
class="w-full text-sm font-medium text-gray-800 text-start group-hover:text-white line-clamp-1">
{{ menu.name }}
</span>
<span
class="w-full text-xs text-gray-500 text-start group-hover:text-white line-clamp-1">
{{ menu.path.replace('/home/', '') }}
</span>
</div>
<span class="hidden ml-3 text-sm text-gray-500 group-hover:block group-hover:text-white">
Buka
</span>
</div>
<span v-if="active" class="flex-none ml-3 text-gray-200">
Buka
</span>
</li>
</ComboboxOption>
@ -146,7 +148,7 @@
</template>
<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { computed, ref } from 'vue'
import { MagnifyingGlassIcon } from '@heroicons/vue/20/solid'
import {
Combobox,

57
src/components/DatePicker.vue Normal file → Executable file
View File

@ -1,41 +1,54 @@
<script setup lang="ts">
import { PhCalendarBlank } from '@phosphor-icons/vue';
import { ref } from 'vue'
import VueTailwindDatepicker from 'vue-tailwind-datepicker'
import { PhCalendarBlank } from '@phosphor-icons/vue'
import { ref, watch } from 'vue'
import VueTailwindDatepicker from 'vue-tailwind-datepicker'
const dateValue = ref('')
const formatter = ref({
date: 'DD MMM YYYY',
month: 'MMM'
date: 'DD-MM-YYYY',
month: 'MMMM'
})
const emit = defineEmits(['update:dateValue'])
const customShortcuts = () => {
return [
{
label: 'Last 15 Days',
atClick: () => {
const date = new Date()
return [new Date(date.setDate(date.getDate() - 15)), new Date()]
}
},
{
label: 'Last Years',
atClick: () => {
const date = new Date()
return [new Date(date.setFullYear(date.getFullYear() - 1)), new Date()]
}
}
]
}
watch(dateValue, (newValue) => {
emit('update:dateValue', newValue)
})
</script>
<template>
<div class="flex">
<vue-tailwind-datepicker
v-model="dateValue"
:formatter="formatter"
separator=" s/d "
:shortcuts="false"
:auto-apply="false"
as-single
use-range
v-slot="{ value, placeholder }"
>
<vue-tailwind-datepicker v-model="dateValue" :formatter="formatter" separator=" s/d " :shortcuts="customShortcuts"
:auto-apply="true" as-single use-range v-slot="{ value, placeholder }">
<div class="flex">
<div class="flex-1">
<button
type="button"
class="w-full flex items-center justify-between px-4 py-2 text-sm leading-6 placeholder:text-gray-400 text-gray-900 border-0 border-transparent rounded-lg outline-0 bg-gray-200 focus:outline-0 focus:border-0 focus:ring-0"
>
<button type="button"
class="flex items-center justify-between w-full px-4 py-2 text-sm leading-6 text-gray-900 bg-gray-200 border-0 border-transparent rounded-lg placeholder:text-gray-400 outline-0 focus:outline-0 focus:border-0 focus:ring-0">
<span class="text-gray-900">
{{ value || placeholder }}
</span>
<PhCalendarBlank size="18" weight="regular"/>
<PhCalendarBlank size="18" weight="regular" />
</button>
</div>
</div>
</vue-tailwind-datepicker>
</div>
</template>
</template>

0
src/components/Dialogs/ActionDialog.vue Normal file → Executable file
View File

13
src/components/Dialogs/DetailDialog.vue Normal file → Executable file
View File

@ -5,7 +5,7 @@ import {
DialogTitle,
TransitionChild,
TransitionRoot
} from '@headlessui/vue'
} from '@headlessui/vue';
defineProps({
open: {
type: Boolean,
@ -15,6 +15,10 @@ defineProps({
type: String,
required: true,
},
fullWidth: {
type: Boolean,
default: false,
},
})
const emit = defineEmits(['onClose'])
const handleOnClose = () => {
@ -38,12 +42,13 @@ const handleOnClose = () => {
leave-from="opacity-100 translate-y-0 sm:scale-100"
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95">
<DialogPanel
:class="['sm:max-w-lg relative overflow-hidden text-left transition-all transform bg-gray-50 rounded-2xl sm:my-8 sm:w-full']">
:class="[fullWidth ? 'sm:max-w-full' : 'sm:max-w-lg sm:my-8', 'relative overflow-hidden text-left transition-all transform bg-gray-50 rounded-2xl sm:w-full']">
<!-- Body Section -->
<div class="px-4 py-4 bg-gray-50">
<div class="flex flex-col items-start">
<div class="items-start">
<div class="flex items-start justify-between w-full">
<DialogTitle as="h3" class="flex-1 text-2xl font-semibold leading-6 text-gray-900">
<DialogTitle as="h3"
class="flex-1 text-2xl font-semibold leading-6 text-gray-900">
{{ title }}
</DialogTitle>
<div class="flex items-center ml-3 h-7">

48
src/components/Form/Filters.vue Normal file → Executable file
View File

@ -1,44 +1,38 @@
<script setup lang="ts">
// components
import Button from '@/components/Button.vue';
import Button from '@/components/Buttons/Button.vue';
import { PhArrowsCounterClockwise, PhFileText, PhMagnifyingGlass } from '@phosphor-icons/vue';
// icons
import {
PhArrowsCounterClockwise,
PhFileText,
PhMagnifyingGlass
} from '@phosphor-icons/vue';
defineProps({
reportButton: {
type: Boolean,
default: false
}
})
defineProps({
reportButton: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['runSearch', 'resetForm', 'runReport'])
</script>
<template>
<div class="filters rounded-2xl">
<form class="filter-body bg-gray-50 mx-auto space-y-3 p-4 rounded-t-2xl">
<form class="p-4 mx-auto space-y-3 filter-body bg-gray-50 rounded-t-2xl">
<slot></slot>
</form>
<div class="filter-footer rounded-b-2xl px-4 py-3 bg-primary-50 flex justify-end">
<div class="filter-buttons flex gap-3 flex-wrap">
<Button label="Ulangi" style-type="outline" class-name="bg-white">
<PhArrowsCounterClockwise size="18" class="ml-1" weight="regular" />
<div class="flex justify-end px-4 py-3 filter-footer rounded-b-2xl bg-primary-50">
<div class="flex flex-wrap gap-3 filter-buttons">
<Button @on:click="() => emit('resetForm')" label="Ulangi" style-type="outline" class-name="bg-white !text-xs">
<PhArrowsCounterClockwise size="16" class="ml-1" weight="regular" />
</Button>
<Button v-if="reportButton" label="Lihat Laporan" style-type="outline" class-name="bg-white">
<PhFileText size="18" class="ml-1" weight="regular" />
<Button v-if="reportButton" label="Lihat Laporan" style-type="outline" class-name="bg-white !text-xs"
@on:click="() => emit('runReport')">
<PhFileText size="16" class="ml-1" weight="regular" />
</Button>
<Button label="Cari Data">
<PhMagnifyingGlass size="18" class="ml-1" weight="regular" />
<Button @on:click="() => emit('runSearch')" label="Cari Data" class-name="!text-xs">
<PhMagnifyingGlass size="16" class="ml-1" weight="regular" />
</Button>
</div>
</div>
</div>
</template>
</template>

103
src/components/Form/FiltersType/Type1.vue Normal file → Executable file
View File

@ -1,32 +1,87 @@
<script setup lang="ts">
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import Select from '@/components/Select.vue';
import DatePicker from '@/components/DatePicker.vue';
import {
selectedUid,
selectedUp3Posko,
selectedPosko,
itemsUid,
itemsUp3,
itemsPosko,
fetchUid
} from './reference';
import { onMounted, ref, watch } from 'vue';
const uidPlaceholder = 'Semua Unit Induk Distribusi/Wilayah'
const up3placeholder = 'Semua Unit Pelaksanaan Pelayanan Pelanggan'
const poskoPlaceholder = 'Semua Posko'
const up3 = ref({ id: 0, name: up3placeholder })
const uid = ref({ id: 0, name: uidPlaceholder })
const posko = ref({ id: 0, name: poskoPlaceholder })
const emit = defineEmits(['update:filters'])
const data = ref({
uid: uid.value,
up3: up3.value,
posko: posko.value,
periode: ''
})
watch(data.value, (value) => {
emit('update:filters', value)
})
const setUid = (value: any) => {
uid.value = value
selectedUid(value)
up3.value = { id: 0, name: up3placeholder }
data.value.uid = value
}
const setUp3 = (value: any) => {
up3.value = value
selectedUp3Posko(value)
console.log(itemsPosko)
posko.value = { id: 0, name: poskoPlaceholder }
data.value.up3 = value
}
const setPosko = (value: any) => {
posko.value = value
selectedPosko(value)
data.value.posko = value
}
onMounted(() => {
fetchUid()
emit('update:filters', data.value)
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit Induk Distribusi/Wilayah:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Induk Distribusi/Wilayah:</label>
<Select placeholder="Semua Unit Induk Distribusi/Wilayah"/>
<Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
<Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="up3" :placeholder="up3placeholder" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Posko:</label>
<Select @update:selected="setPosko($event)" :data="itemsPosko" :selected="posko"
:placeholder="poskoPlaceholder" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode Tanggal:</label>
<DatePicker @update:date-value="(value) => (data.periode = value)" />
</div>
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Posko:</label>
<Select placeholder="Semua Posko" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label>
<DatePicker />
</div>
</template>

106
src/components/Form/FiltersType/Type10.vue Normal file → Executable file
View File

@ -1,44 +1,94 @@
<script setup lang="ts">
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import { onMounted, ref } from 'vue'
import {
selectedUid,
selectedUp3Ulp,
selectedUlp,
fetchUid,
itemsUid,
itemsUp3,
itemsUlp
} from './reference'
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import InputNumber from '@/components/Form/InputNumber.vue'
const uidPlaceholder = 'Semua Unit Induk Distribusi/Wilayah'
const up3Placeholder = 'Semua Unit Pelaksanaan Pelayanan Pelanggan'
const ulpPlaceholder = 'Semua Unit Layanan Pelanggan'
const up3 = ref({ id: 0, name: up3Placeholder })
const uid = ref({ id: 0, name: uidPlaceholder })
const ulp = ref({ id: 0, name: ulpPlaceholder })
const emit = defineEmits(['update:filters'])
const data = ref({
uid: uid.value,
up3: up3.value,
ulp: ulp.value,
periode: '',
minJmlLapor: 1,
maxJmlLapor: 1
})
const setUid = (value: any) => {
uid.value = value
selectedUid(value)
up3.value = { id: 0, name: up3Placeholder }
data.value.uid = value
}
const setUp3 = (value: any) => {
up3.value = value
selectedUp3Ulp(value)
ulp.value = { id: 0, name: ulpPlaceholder }
data.value.up3 = value
}
const setUlp = (value: any) => {
ulp.value = value
selectedUlp(value)
data.value.ulp = value
}
onMounted(() => {
emit('update:filters', data.value)
fetchUid()
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit Induk Distribusi/Wilayah:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Induk Distribusi/Wilayah:</label>
<Select placeholder="Semua Unit Induk Distribusi/Wilayah"/>
</div>
<Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" />
</div>
<Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="up3" :placeholder="up3Placeholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Layanan Pelanggan:</label
>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Layanan Pelanggan:</label>
<Select placeholder="Semua Unit Layanan Pelanggan" />
</div>
<Select @update:selected="setUlp($event)" :data="itemsUlp" :selected="ulp" :placeholder="ulpPlaceholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode Tanggal:</label>
<DatePicker />
</div>
<DatePicker @update:date-value="(value) => (data.periode = value)" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Lapor Ulang:</label>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Lapor Ulang:</label>
<div class="grid grid-flow-col auto-cols-auto gap-x-1.5">
<Select placeholder="1" />
<small class="flex items-center">s/d</small>
<Select placeholder="2" />
<div class="flex flex-1 justify-between gap-x-1.5">
<InputNumber @update:time-value="(value) => (data.minJmlLapor = value)" class="flex flex-1" />
<small class="flex items-center">s/d</small>
<InputNumber @update:time-value="(value) => (data.maxJmlLapor = value)" class="flex flex-1" />
</div>
</div>
</div>
</template>

204
src/components/Form/FiltersType/Type11.vue Normal file → Executable file
View File

@ -1,47 +1,191 @@
<script setup lang="ts">
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
interface SlaOption {
id: number
name: string
min: string
max: string
}
import { onMounted, ref } from 'vue'
import {
selectedUid,
selectedUp3Ulp,
selectedUlp,
fetchUid,
itemsUid,
itemsUp3,
itemsUlp
} from './reference'
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import InputWithSuffix from '@/components/Form/InputWithSuffix.vue'
const props = defineProps({
slaOptions: {
type: Array as () => SlaOption[],
default: [
{
id: 1,
name: 'Dibawah / Sesuai SLA (<= 45 menit)',
min: '1',
max: '45'
},
{
id: 2,
name: 'Melebihi SLA (> 45 menit)',
min: '46',
max: `${99999 * 60 * 24}`
}
]
}
})
const sla = props.slaOptions.map((item: any) => {
return {
id: item.id,
name: item.name
}
})
const totalMin = ref('1 Menit')
const totalMax = ref('5 Menit')
const uidPlaceholder = 'Semua Unit Induk Distribusi/Wilayah'
const up3Placeholder = 'Semua Unit Pelaksanaan Pelayanan Pelanggan'
const ulpPlaceholder = 'Semua Unit Layanan Pelanggan'
const up3 = ref({ id: 0, name: up3Placeholder })
const uid = ref({ id: 0, name: uidPlaceholder })
const ulp = ref({ id: 0, name: ulpPlaceholder })
const emit = defineEmits(['update:filters'])
const isHidden = ref(false)
const setDataMin = (value: any) => (totalMin.value = value)
const getDataMin = () => totalMin.value
const setDataMax = (value: any) => (totalMax.value = value)
const getDataMax = () => totalMax.value
const data = ref({
uid: uid.value,
up3: up3.value,
ulp: ulp.value,
periode: '',
minTime: getDataMin().split(' ')[0],
maxTime: getDataMax().split(' ')[0]
})
const setUid = (value: any) => {
uid.value = value
selectedUid(value)
up3.value = { id: 0, name: up3Placeholder }
data.value.uid = value
}
const setUp3 = (value: any) => {
up3.value = value
selectedUp3Ulp(value)
ulp.value = { id: 0, name: ulpPlaceholder }
data.value.up3 = value
}
const setUlp = (value: any) => {
ulp.value = value
selectedUlp(value)
data.value.ulp = value
}
const setMin = (value: any) => {
console.log(value)
data.value.minTime = value
setDataMin(value)
}
const setMax = (value: any) => {
data.value.maxTime = value
setDataMax(value)
}
const triggerInput = ref(false)
const changeDuration = (value: any) => {
if (value.id === 0) {
setMin('1')
setMax('5')
triggerInput.value = false
isHidden.value = false
} else if (value.id === 1) {
setMin(props.slaOptions[0].min)
setMax(props.slaOptions[0].max)
triggerInput.value = true
isHidden.value = true
} else {
setMin(props.slaOptions[1].min)
setMax(props.slaOptions[1].max)
triggerInput.value = true
isHidden.value = true
}
}
onMounted(() => {
emit('update:filters', data.value)
fetchUid()
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit Induk Distribusi/Wilayah:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Induk Distribusi/Wilayah:</label>
<Select placeholder="Semua Unit Induk Distribusi/Wilayah"/>
</div>
<Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" />
</div>
<Select
@update:selected="setUp3($event)"
:data="itemsUp3"
:selected="up3"
:placeholder="up3Placeholder"
/>
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Layanan Pelanggan:</label
>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Layanan Pelanggan:</label>
<Select placeholder="Semua Unit Layanan Pelanggan" />
</div>
<Select
@update:selected="setUlp($event)"
:data="itemsUlp"
:placeholder="ulpPlaceholder"
:selected="ulp"
/>
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode Tanggal:</label>
<DatePicker />
</div>
<DatePicker @update:date-value="(value) => (data.periode = value)" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Durasi:</label>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Durasi:</label>
<div class="flex flex-col gap-y-1">
<Select placeholder="Durasi Menit" />
<div class="flex flex-col gap-y-2">
<Select @update:selected="changeDuration($event)" :data="sla" placeholder="Durasi Menit" />
<div class="grid grid-flow-col auto-cols-auto gap-x-1.5">
<Select placeholder="1" />
<small class="flex items-center">s/d</small>
<Select placeholder="2" />
<div class="flex flex-1 justify-between gap-x-1.5" :class="[isHidden ? 'hidden' : '']">
<InputWithSuffix
:value="`${data.minTime} Menit`"
@update:text="setMin($event)"
class="flex flex-1"
/>
<small class="flex items-center">s/d</small>
<InputWithSuffix
:value="`${data.maxTime} Menit`"
@update:text="setMax($event)"
class="flex flex-1"
/>
</div>
</div>
</div>
</div>

139
src/components/Form/FiltersType/Type12.vue Normal file → Executable file
View File

@ -1,49 +1,124 @@
<script setup lang="ts">
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import InputWithSuffix from '../InputWithSuffix.vue';
import Select from '@/components/Select.vue';
import DatePicker from '@/components/DatePicker.vue';
import InputWithSuffix from '../InputWithSuffix.vue';
import { selectedUid, selectedUp3Ulp, selectedUlp, fetchUid, itemsUid, itemsUp3, itemsUlp } from './reference';
import { onMounted, ref } from 'vue';
const uidPlaceholder = 'Semua Unit Induk Distribusi/Wilayah';
const up3Placeholder = 'Semua Unit Pelaksanaan Pelayanan Pelanggan';
const ulpPlaceholder = 'Semua Unit Layanan Pelanggan';
const uppp = ref({ id: 0, name: up3Placeholder });
const uid = ref({ id: 0, name: uidPlaceholder });
const ulp = ref({ id: 0, name: ulpPlaceholder });
const emit = defineEmits(['update:filters'])
const data = ref({
uid: uid.value,
up3: uppp.value,
ulp: ulp.value,
periode: '',
minDurasiResponseTime: 1,
maxDurasiResponseTime: 1
})
const setUid = (value: any) => {
uid.value = value;
selectedUid(value);
uppp.value = { id: 0, name: up3Placeholder };
data.value.uid = value;
};
const setUp3 = (value: any) => {
uppp.value = value;
selectedUp3Ulp(value);
ulp.value = { id: 0, name: ulpPlaceholder };
data.value.up3 = value;
};
const setUlp = (value: any) => {
ulp.value = value;
selectedUlp(value);
data.value.ulp = value;
};
const triggerInput = ref(false)
const sla = [
{
id: 0,
name: 'Durasi Menit'
},
{
id: 1,
name: 'Dibawah / Sesuai SLA (<= 45 menit)'
},
{
id: 2,
name: 'Melebihi SLA (> 45 menit)'
}
];
const changeDuration = (value: any) => {
if (value.id === 0) {
console.log('Durasi Menit')
data.value.minDurasiResponseTime = 0
data.value.maxDurasiResponseTime = 5
triggerInput.value = false
} else if (value.id === 1) {
data.value.minDurasiResponseTime = 0
data.value.maxDurasiResponseTime = 45
console.log('Dibawah / Sesuai SLA (<= 45 menit)')
triggerInput.value = true
} else {
data.value.minDurasiResponseTime = 46
data.value.maxDurasiResponseTime = 99999 * 60 * 24
triggerInput.value = true
console.log('Melebihi SLA (> 45 menit)')
}
}
onMounted(() => {
emit('update:filters', data.value)
fetchUid()
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit Induk Distribusi/Wilayah:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Induk Distribusi/Wilayah:</label>
<Select placeholder="Semua Unit Induk Distribusi/Wilayah"/>
</div>
<Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" />
</div>
<Select @update:selected="setUp3($event)" :data="itemsUp3" :placeholder="up3Placeholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Layanan Pelanggan:</label
>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Layanan Pelanggan:</label>
<Select placeholder="Semua Unit Layanan Pelanggan" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label>
<Select @update:selected="setUlp($event)" :data="itemsUlp" :placeholder="ulpPlaceholder" />
</div>
<DatePicker />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode Tanggal:</label>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Durasi:</label>
<DatePicker @update:date-value="(value) => data.periode = value" />
</div>
<div class="flex flex-col gap-y-1">
<Select placeholder="Durasi Menit" />
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Durasi:</label>
<div class="grid grid-flow-col auto-cols-auto gap-x-1.5">
<InputWithSuffix />
<small class="flex items-center">s/d</small>
<InputWithSuffix />
<div class="flex flex-col gap-y-1">
<Select @update:selected="changeDuration($event)" :data="sla" placeholder="Durasi Menit" />
<div class="flex flex-1 justify-between gap-x-1.5">
<InputWithSuffix @update:minute-value="(value: any) => data.minDurasiResponseTime = value" @value="data.minDurasiResponseTime" :disabled=triggerInput
class="flex flex-1" />
<small class="flex items-center">s/d</small>
<InputWithSuffix @update:minute-value="(value: any) => data.maxDurasiResponseTime = value" @value="data.maxDurasiResponseTime"
:disabled="triggerInput" class="flex flex-1" />
</div>
</div>
</div>
</div>
</template>

118
src/components/Form/FiltersType/Type13.vue Normal file → Executable file
View File

@ -1,41 +1,93 @@
<script setup lang="ts">
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import InlineRadioGroup from '@/components/Form/InlineRadioGroup.vue'
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import InlineRadioGroup from '@/components/Form/InlineRadioGroup.vue'
import {
selectedUid,
selectedUp3Ulp,
selectedUlp,
fetchUid,
itemsUid,
itemsUp3,
itemsUlp
} from './reference'
import { onMounted, ref } from 'vue'
const uidPlaceholder = 'Semua Unit Induk Distribusi/Wilayah'
const up3Placeholder = 'Semua Unit Pelaksanaan Pelayanan Pelanggan'
const ulpPlaceholder = 'Semua Unit Layanan Pelanggan'
const up3 = ref({ id: 0, name: up3Placeholder })
const uid = ref({ id: 0, name: uidPlaceholder })
const ulp = ref({ id: 0, name: ulpPlaceholder })
const emit = defineEmits(['update:filters'])
const data = ref({
uid: uid.value,
up3: up3.value,
ulp: ulp.value,
periode: '',
groupBy: false
})
const setUid = (value: any) => {
uid.value = value
selectedUid(value)
up3.value = { id: 0, name: up3Placeholder }
data.value.uid = value
}
const setUp3 = (value: any) => {
up3.value = value
selectedUp3Ulp(value)
ulp.value = { id: 0, name: ulpPlaceholder }
data.value.up3 = value
}
const setUlp = (value: any) => {
ulp.value = value
selectedUlp(value)
data.value.ulp = value
console.log('data.value', data.value)
}
onMounted(() => {
emit('update:filters', data.value)
fetchUid()
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit Induk Distribusi/Wilayah:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Induk Distribusi/Wilayah:</label>
<Select placeholder="Semua Unit Induk Distribusi/Wilayah"/>
<Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
<Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="up3" :placeholder="up3Placeholder" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Layanan Pelanggan:</label>
<Select @update:selected="setUlp($event)" :data="itemsUlp" :selected="ulp" :placeholder="ulpPlaceholder" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode Tanggal:</label>
<DatePicker @update:date-value="(value) => (data.periode = value)" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Group By Kode Unit Distribusi:</label>
<InlineRadioGroup @update:group-value="(value) => (data.groupBy = value.id === 2)" :radio-items="[
{ id: 1, title: 'Tidak' },
{ id: 2, title: 'Ya, Grupkan' }
]" />
</div>
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Layanan Pelanggan:</label
>
<Select placeholder="Semua Unit Layanan Pelanggan" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label>
<DatePicker />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Group By Kode Unit Distribusi:</label>
<InlineRadioGroup :radio-items="[{id: 1, title: 'Tidak', checked: true}, {id: 2, title: 'Ya, Grupkan'}]" />
</div>
</template>

90
src/components/Form/FiltersType/Type14.vue Normal file → Executable file
View File

@ -1,34 +1,72 @@
<script setup lang="ts">
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import Select from '@/components/Select.vue';
import DatePicker from '@/components/DatePicker.vue';
import { selectedUid, selectedUp3Posko, selectedPosko, fetchUid, itemsUid, itemsUp3, itemsPosko } from './reference';
import { onMounted, ref } from 'vue';
const uidPlaceholder = 'Semua Distribusi/Wilayah';
const up3Placeholder = 'Semua Area';
const poskoPlaceholder = 'Semua Unit Layanan Pelanggan';
const up3 = ref({ id: 0, name: up3Placeholder });
const uid = ref({ id: 0, name: uidPlaceholder });
const posko = ref({ id: 0, name: poskoPlaceholder });
const emit = defineEmits(['update:filters'])
const data = ref({
uid: uid.value,
up3: up3.value,
posko: posko.value,
periode: '',
})
const setUid = (value: any) => {
uid.value = value;
selectedUid(value);
up3.value = { id: 0, name: up3Placeholder };
data.value.uid = value;
};
const setUp3 = (value: any) => {
up3.value = value;
selectedUp3Posko(value);
posko.value = { id: 0, name: poskoPlaceholder };
data.value.up3 = value;
};
const setPosko = (value: any) => {
posko.value = value;
selectedPosko(value);
data.value.posko = value;
};
onMounted(() => {
emit('update:filters', data.value)
fetchUid()
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Distribusi/Wilayah:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Distribusi/Wilayah:</label>
<Select :data="itemsUid" @update:selected="setUid($event)" :placeholder="uidPlaceholder" :selected="uid" />
</div>
<Select placeholder="Semua Distribusi/Wilayah"/>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Area:</label>
<Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="up3" :placeholder="up3Placeholder" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Posko:</label>
<Select @update:selected="setPosko($event)" :data="itemsPosko" :selected="posko"
:placeholder="poskoPlaceholder" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode Tanggal:</label>
<DatePicker @update:date-value="(value) => data.periode = value" />
</div>
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Area:</label
>
<Select placeholder="Semua Area" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Posko:</label
>
<Select placeholder="Semua Posko" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label>
<DatePicker />
</div>
</template>

79
src/components/Form/FiltersType/Type15.vue Normal file → Executable file
View File

@ -1,25 +1,76 @@
<script setup lang="ts">
import InputWithFilter from '../InputWithFilter.vue'
import DatePicker from '@/components/DatePicker.vue'
import InlineRadioGroup from '@/components/Form/InlineRadioGroup.vue'
import InputWithFilter from '../InputWithFilter.vue'
import DatePicker from '@/components/DatePicker.vue'
import InlineRadioGroup from '@/components/Form/InlineRadioGroup.vue'
import { onMounted, ref } from 'vue'
const type = ref('Gangguan')
const keyword = ref('')
const reportType = [
{ id: 1, title: 'Nomor Laporan' },
{ id: 2, title: 'Nama Pelapor' },
{ id: 3, title: 'No Telepon' },
{ id: 4, title: 'Alamat' },
{ id: 5, title: 'Pembuat' }
]
const searchBy = ref<any>(reportType[0].title)
const emit = defineEmits(['update:filters'])
const data = ref({
type: type.value,
keyword: keyword.value,
searchBy: searchBy.value,
periode: ''
})
const changeKeyword = (value: string) => {
keyword.value = value
data.value.keyword = value
}
const changeReportTypeSelected = (id: any) => {
searchBy.value = reportType.find((item) => item.id == id)?.title
data.value.searchBy = searchBy.value
}
const setPengaduan = (value: any) => {
type.value = value.title
data.value.type = value.title
}
onMounted(() => {
emit('update:filters', data.value)
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Jenis Pengaduan:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Jenis Pengaduan:</label>
<InlineRadioGroup :radio-items="[{id: 1, title: 'Gangguan', checked: true}, {id: 2, title: 'Keluhan'}]" />
</div>
<InlineRadioGroup
@update:group-value="setPengaduan"
:radio-items="[
{ id: 1, title: 'Gangguan', checked: true },
{ id: 2, title: 'Keluhan' }
]"
/>
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Cari Report Number:</label>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Cari Report Number:</label>
<InputWithFilter placeholder="cari report" :filters="[{id: 1, title: 'Nama Pelapor'}]" />
</div>
<InputWithFilter
placeholder="Cari Report"
:filters="reportType"
@update:keyword="changeKeyword"
@update:filters="changeReportTypeSelected"
/>
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label>
<div class="flex flex-col flex-1 space-y-2" v-if="searchBy != 'Nomor Laporan'">
<label class="filter-input-label">Periode Tanggal:</label>
<DatePicker />
<DatePicker @update:date-value="(value) => (data.periode = value)" />
</div>
</div>
</template>

127
src/components/Form/FiltersType/Type16.vue Normal file → Executable file
View File

@ -1,38 +1,105 @@
<script setup lang="ts">
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import Select from '@/components/Select.vue';
import DatePicker from '@/components/DatePicker.vue';
import {
selectedUid,
selectedUp3Posko,
selectedPosko,
fetchUid,
fetchMedia,
itemsUid,
itemsUp3,
itemsPosko,
itemsMedia
} from './reference';
import { onMounted, ref, watch } from 'vue';
const uidPlaceholder = 'Semua Unit Induk Distribusi/Wilayah'
const up3Placeholder = 'Semua Unit Pelaksanaan Pelayanan Pelanggan'
const poskoPlaceholder = 'Semua Posko'
const mediaPlaceholder = 'Semua Media'
const up3 = ref({ id: 0, name: up3Placeholder })
const uid = ref({ id: 0, name: uidPlaceholder })
const posko = ref({ id: 0, name: poskoPlaceholder })
const media = ref({ id: '', name: mediaPlaceholder })
const emit = defineEmits(['update:filters'])
const data = ref({
uid: uid.value,
up3: up3.value,
posko: posko.value,
media: media.value,
periode: ''
})
watch(data.value, (value) => {
emit('update:filters', value)
})
const setUid = (value: any) => {
uid.value = value
selectedUid(value)
up3.value = { id: 0, name: up3Placeholder }
data.value.uid = value
}
const setUp3 = (value: any) => {
up3.value = value
selectedUp3Posko(value)
posko.value = { id: 0, name: poskoPlaceholder }
data.value.up3 = value
}
const setPosko = (value: any) => {
posko.value = value
selectedPosko(value)
data.value.posko = value
}
const setMedia = (value: any) => {
media.value = value
data.value.media = value
}
onMounted(() => {
emit('update:filters', data.value)
fetchUid()
fetchMedia()
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit Induk Distribusi/Wilayah:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Induk Distribusi/Wilayah:</label>
<Select placeholder="Semua Unit Induk Distribusi/Wilayah"/>
<Select :data="itemsUid" @update:selected="setUid($event)" :placeholder="uidPlaceholder" :selected="uid" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
<Select :data="itemsUp3" @update:selected="setUp3($event)" :placeholder="up3Placeholder" :selected="up3" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Posko:</label>
<Select :data="itemsPosko" @update:selected="setPosko($event)" :placeholder="poskoPlaceholder"
:selected="posko" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Media:</label>
<Select :selected="media" @update:selected="setMedia($event)" :placeholder="mediaPlaceholder"
:data="itemsMedia" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode Tanggal:</label>
<DatePicker @update:date-value="(value) => (data.periode = value)" />
</div>
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Posko:</label>
<Select placeholder="Semua Posko" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Media:</label>
<Select placeholder="Semua Media" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label>
<DatePicker />
</div>
</template>

71
src/components/Form/FiltersType/Type17.vue Normal file → Executable file
View File

@ -1,46 +1,51 @@
<script setup lang="ts">
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import InputWithFilter from '../InputWithFilter.vue'
import Select from '@/components/Select.vue';
import DatePicker from '@/components/DatePicker.vue';
import InputWithFilter from '../InputWithFilter.vue';
import { ref } from 'vue';
const data = ref({
periode: '',
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode Tanggal:</label>
<DatePicker />
</div>
<DatePicker @update:date-value="(value) => data.periode = value" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit PLN:</label>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit PLN:</label>
<div class="flex flex-col gap-y-1">
<Select placeholder="Pilih Unit" />
<div class="flex flex-col gap-y-1">
<Select placeholder="Pilih Unit" />
<div class="grid grid-flow-col auto-cols-auto gap-x-1.5">
<Select placeholder="Pilih Area" />
<Select placeholder="Pilih Rayon" />
<div class="grid grid-flow-col auto-cols-auto gap-x-1.5">
<Select placeholder="Pilih Area" />
<Select placeholder="Pilih Rayon" />
</div>
</div>
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Status:</label>
<Select placeholder="Pilih Status" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">SLA:</label>
<Select placeholder="Pilih Durasi SLA" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Pencarian:</label>
<InputWithFilter placeholder="cari report" :filters="[{ id: 1, title: 'Pilih Jenis' }]" />
</div>
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Status:</label>
<Select placeholder="Pilih Status"/>
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>SLA:</label
>
<Select placeholder="Pilih Durasi SLA" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Pencarian:</label>
<InputWithFilter placeholder="cari report" :filters="[{id: 1, title: 'Pilih Jenis'}]" />
</div>
</template>

View File

@ -0,0 +1,68 @@
<script setup lang="ts">
import Select from '@/components/Select.vue';
import SelectMulti from '@/components/SelectMulti.vue';
import DatePicker from '@/components/DatePicker.vue';
import { selectedUid, selectedUp3Posko, selectedPosko, fetchUid, itemsUid, itemsUp3, itemsPosko } from './reference';
import { onMounted, ref } from 'vue';
const uidPlaceholder = 'Semua Unit Induk Distribusi/Wilayah';
const up3Placeholder = 'Semua Unit Pelaksanaan Pelayanan Pelanggan';
const poskoPlaceholder = 'Semua Posko';
const up3 = ref({ id: 0, name: up3Placeholder });
const uid = ref({ id: 0, name: uidPlaceholder });
const posko = ref({ id: 0, name: poskoPlaceholder });
const emit = defineEmits(['update:filters'])
const jenisTransakasi = [
{ id: 1, value: 'Koreksi Transaksi Individual', label: 'Koreksi Transaksi Individual' },
{ id: 2, value: 'Cleansing Traksaksi TM', label: 'Cleansing Traksaksi TM', },
{ id: 3, value: 'Koreksi Transaksi TM', label: 'Koreksi Transaksi TM', },
{ id: 4, value: 'Koreksi Kode Gangguan dan Anev', label: 'Koreksi Kode Gangguan dan Anev' },
]
const data = ref({
uid: uid.value,
up3: up3.value,
posko: posko.value,
periode: '',
jenisTransaksi: [],
group: 1
})
onMounted(() => {
emit('update:filters', data.value)
fetchUid()
})
</script>
<template>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Induk Distribusi/Wilayah:</label>
<Select @update:selected="selectedUid($event)" :data="itemsUid"
placeholder="Semua Unit Induk Distribusi/Wilayah" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
<Select @update:selected="selectedUp3Posko($event)" :data="itemsUp3" :selected="up3"
placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Posko:</label>
<Select @update:selected="selectedPosko($event)" :data="itemsPosko" :selected="posko" placeholder="Semua Posko" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Jenis Transaksi:</label>
<SelectMulti :tags="jenisTransakasi" placeholder="Semua Jenis Transaksi" useLabel label="Jenis Transaksi" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode Tanggal:</label>
<DatePicker @update:date-value="(value) => data.periode = value" />
</div>
</div>
</template>

147
src/components/Form/FiltersType/Type2.vue Normal file → Executable file
View File

@ -1,42 +1,137 @@
<script setup lang="ts">
import Select from '@/components/Select.vue'
import Select from '@/components/Select.vue';
import {
selectedUid,
selectedUp3Ulp,
fetchRegional,
fetchUid, itemsUid,
itemsUp3,
itemsUlp,
itemsRegional,
months,
years
} from './reference';
import { onMounted, ref } from 'vue';
import { getMonthName } from '@/utils/texts';
const uidPlaceholder = 'Semua Unit Induk Distribusi/Wilayah'
const up3Placholder = 'Semua Unit Pelaksanaan Pelayanan Pelanggan'
const ulpPlaceholder = 'Semua Unit Layanan Pelanggan'
const regionalPlaceholder = 'Semua Regional'
const bulanPlaceholder = getMonthName(new Date().getMonth())
const tahunPlaceholder = new Date().getFullYear().toString()
const bulanSelected = new Date().getMonth()
const tahunSelected = new Date().getFullYear()
const uppp = ref({ id: 0, name: up3Placholder })
const uid = ref({ id: 0, name: uidPlaceholder })
const ulp = ref({ id: 0, name: ulpPlaceholder })
const bulan = ref({ id: bulanSelected, name: bulanPlaceholder })
const tahun = ref({ id: tahunSelected, name: tahunPlaceholder })
const regional = ref({ id: 0, name: regionalPlaceholder })
const emit = defineEmits(['update:filters'])
// Find index of January
const bulanIndex = months.findIndex((month) => month.id === bulan.value.id)
console.log(bulanSelected)
// Remove January if found
if (bulanIndex !== -1) {
months.splice(bulanIndex, 1)
}
// Find index of current year
const tahunIndex = years.value.findIndex((year) => year.id === tahun.value.id)
if (tahunIndex !== -1) {
years.value.splice(tahunIndex, 1)
}
const data = ref({
regional: regional.value,
uid: uid.value,
up3: uppp.value,
ulp: ulp.value,
periode: '',
bulan: bulan.value,
tahun: tahun.value
})
const setRegional = (value: any) => {
regional.value = value
fetchUid()
// harusnya fetchUidWithRegional(value);
selectedUid(value)
uid.value = { id: 0, name: uidPlaceholder }
data.value.regional = value
}
const setUid = (value: any) => {
uid.value = value
selectedUid(value)
uppp.value = { id: 0, name: up3Placholder }
data.value.uid = value
}
const setUp3 = (value: any) => {
uppp.value = value
selectedUp3Ulp(value)
ulp.value = { id: 0, name: ulpPlaceholder }
data.value.up3 = value
}
const setUlp = (value: any) => {
ulp.value = value
selectedUp3Ulp(value)
data.value.ulp = value
}
const setMonth = (value: any) => {
bulan.value = value
data.value.bulan = value
console.log(data.value)
}
const setYear = (value: any) => {
tahun.value = value
data.value.tahun = value
}
onMounted(() => {
emit('update:filters', data.value)
fetchRegional()
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Regional:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Regional:</label>
<Select placeholder="Semua Regional"/>
</div>
<Select @update:selected="setRegional($event)" :data="itemsRegional" :placeholder="regionalPlaceholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit Induk Distribusi/Wilayah:</label>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Induk Distribusi/Wilayah:</label>
<Select placeholder="Semua Unit Induk Distribusi/Wilayah"/>
</div>
<Select @update:selected="setUid($event)" :data="itemsUid" :selected="uid" :placeholder="uidPlaceholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" />
</div>
<Select @update:selected="setUp3($event)" :selected="uppp" :data="itemsUp3" :placeholder="up3Placholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Layanan Pelanggan:</label
>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Layanan Pelanggan:</label>
<Select placeholder="Semua Unit Layanan Pelanggan" />
</div>
<Select @update:selected="setUlp($event)" :data="itemsUlp" :selected="ulp" :placeholder="ulpPlaceholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode</label>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode</label>
<div class="grid grid-cols-2 gap-x-2">
<Select placeholder="Juli" />
<Select placeholder="2023" />
<div class="grid grid-cols-2 gap-x-2">
<Select @update:selected="setMonth($event)" :data="months" :placeholder="bulanPlaceholder" />
<Select @update:selected="setYear($event)" :data="years" :placeholder="tahunPlaceholder" />
</div>
</div>
</div>
</template>

106
src/components/Form/FiltersType/Type3.vue Normal file → Executable file
View File

@ -1,34 +1,88 @@
<script setup lang="ts">
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import Select from '@/components/Select.vue';
import DatePicker from '@/components/DatePicker.vue';
import {
selectedUid,
selectedUp3Ulp,
selectedUlp,
fetchUid,
itemsUid,
itemsUp3,
itemsUlp
} from './reference';
import { onMounted, ref, watch } from 'vue';
const uidPlaceholder = 'Semua Unit Induk Distribusi/Wilayah'
const up3Placeholder = 'Semua Unit Pelaksanaan Pelayanan Pelanggan'
const ulpPlaceholder = 'Semua Unit Layanan Pelanggan'
const up3 = ref({ id: 0, name: up3Placeholder })
const uid = ref({ id: 0, name: uidPlaceholder })
const ulp = ref({ id: 0, name: ulpPlaceholder })
const emit = defineEmits(['update:filters'])
const data = ref({
uid: uid.value,
up3: up3.value,
ulp: ulp.value,
periode: ''
})
watch(data.value, (value) => {
emit('update:filters', value)
})
const setUid = (value: any) => {
uid.value = value
selectedUid(value)
up3.value = { id: 0, name: up3Placeholder }
data.value.uid = value
}
const setUp3 = (value: any) => {
up3.value = value
selectedUp3Ulp(value)
ulp.value = { id: 0, name: ulpPlaceholder }
data.value.up3 = value
console.log(itemsUlp)
}
const setUlp = (value: any) => {
ulp.value = value
selectedUlp(value)
data.value.ulp = value
}
onMounted(() => {
fetchUid()
emit('update:filters', data.value)
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit Induk Distribusi/Wilayah:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Induk Distribusi/Wilayah:</label>
<Select placeholder="Semua Unit Induk Distribusi/Wilayah"/>
<Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
<Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="up3" :placeholder="up3Placeholder" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Layanan Pelanggan:</label>
<Select @update:selected="setUlp($event)" :data="itemsUlp" :selected="ulp" :placeholder="ulpPlaceholder" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode Tanggal:</label>
<DatePicker @update:date-value="(value) => (data.periode = value)" />
</div>
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Layanan Pelanggan:</label
>
<Select placeholder="Semua Unit Layanan Pelanggan" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label>
<DatePicker />
</div>
</template>

106
src/components/Form/FiltersType/Type4.vue Normal file → Executable file
View File

@ -1,42 +1,94 @@
<script setup lang="ts">
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import { selectedUid, selectedUp3Ulp, selectedUlp, itemsUid, itemsUp3, itemsUlp } from './reference'
import { computed, onMounted, ref } from 'vue'
const uidPlaceholder = 'Semua Unit Induk Distribusi/Wilayah'
const up3Placeholder = 'Semua Unit Pelaksanaan Pelayanan Pelanggan'
const ulpPlaceholder = 'Semua Unit Layanan Pelanggan'
const uppp = ref({ id: 0, name: up3Placeholder })
const uid = ref({ id: 0, name: uidPlaceholder })
const ulp = ref({ id: 0, name: ulpPlaceholder })
const emit = defineEmits(['update:filters'])
const props = defineProps({
jenisLaporan: {
type: Array as () => any[],
default: () => [
{ id: 1, name: 'Laporan Berulang Unit' },
{ id: 2, name: 'Laporan Berulang Pelanggan' },
{ id: 3, name: 'Laporan Berulang Pelanggan dan Unit' }
]
}
})
const jenisLaporan = ref(computed(() => props.jenisLaporan))
const data = ref({
uid: uid.value,
up3: uppp.value,
ulp: ulp.value,
periode: '',
jenisLaporan: ''
})
const setUid = (value: any) => {
uid.value = value
selectedUid(value)
uppp.value = { id: 0, name: up3Placeholder }
data.value.uid = value
}
const setUp3 = (value: any) => {
uppp.value = value
selectedUp3Ulp(value)
ulp.value = { id: 0, name: ulpPlaceholder }
data.value.up3 = value
}
const setUlp = (value: any) => {
ulp.value = value
selectedUlp(value)
data.value.ulp = value
}
onMounted(() => {
emit('update:filters', data.value)
// fetchUid()
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit Induk Distribusi/Wilayah:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Induk Distribusi/Wilayah:</label>
<Select placeholder="Semua Unit Induk Distribusi/Wilayah"/>
</div>
<Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" />
</div>
<Select @update:selected="setUp3($event)" :data="itemsUp3" :placeholder="up3Placeholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Layanan Pelanggan:</label
>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Layanan Pelanggan:</label>
<Select placeholder="Semua Unit Layanan Pelanggan" />
</div>
<Select @update:selected="setUlp($event)" :data="itemsUlp" :placeholder="ulpPlaceholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Jenis Laporan:</label
>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Jenis Laporan:</label>
<Select placeholder="Laporan Berulang Unit" />
</div>
<Select
@update:selected="(value) => (data.jenisLaporan = value)"
:data="jenisLaporan"
:placeholder="'Semua Jenis Laporan'"
/>
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode Tanggal:</label>
<DatePicker />
<DatePicker @update:date-value="(value) => (data.periode = value)" />
</div>
</div>
</template>

102
src/components/Form/FiltersType/Type5.vue Normal file → Executable file
View File

@ -1,32 +1,86 @@
<script setup lang="ts">
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import { onMounted, ref, watch } from 'vue';
import {
selectedUid,
selectedUp3Posko,
selectedPosko,
fetchUid,
itemsUid,
itemsUp3,
itemsPosko
} from './reference';
import Select from '@/components/Select.vue';
import DatePicker from '@/components/DatePicker.vue';
const uidPlaceholder = 'Semua Unit Induk Distribusi/Wilayah'
const uppPlaceholder = 'Semua Unit Pelaksanaan Pelayanan Pelanggan'
const poskoPlaceholder = 'Semua Posko'
const uppp = ref({ id: 0, name: uppPlaceholder })
const uid = ref({ id: 0, name: uidPlaceholder })
const posko = ref({ id: 0, name: poskoPlaceholder })
const emit = defineEmits(['update:filters'])
const data = ref({
uid: uid.value,
up3: uppp.value,
posko: posko.value,
periode: ''
})
watch(data.value, (value) => {
emit('update:filters', value)
})
const setUid = (value: any) => {
uid.value = value
selectedUid(value)
uppp.value = { id: 0, name: uppPlaceholder }
data.value.uid = value
}
const setUp3 = (value: any) => {
uppp.value = value
selectedUp3Posko(value)
posko.value = { id: 0, name: poskoPlaceholder }
data.value.up3 = value
}
const setPosko = (value: any) => {
posko.value = value
selectedPosko(value)
data.value.posko = value
}
onMounted(() => {
emit('update:filters', data.value)
fetchUid()
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit Induk Distribusi/Wilayah:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Induk Distribusi/Wilayah:</label>
<Select placeholder="Semua Unit Induk Distribusi/Wilayah"/>
<Select :data="itemsUid" @update:selected="setUid($event)" :placeholder="uidPlaceholder" :selected="uid" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
<Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="uppp" :placeholder="uppPlaceholder" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Posko:</label>
<Select @update:selected="setPosko($event)" :data="itemsPosko" :selected="posko"
:placeholder="poskoPlaceholder" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode Tanggal:</label>
<DatePicker @update:date-value="(value) => data.periode = value" />
</div>
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Posko:</label>
<Select placeholder="Semua Posko" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label>
<DatePicker />
</div>
</template>

110
src/components/Form/FiltersType/Type6.vue Normal file → Executable file
View File

@ -1,42 +1,98 @@
<script setup lang="ts">
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import InputNumber from '@/components/Form/InputNumber.vue'
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import {
selectedUid,
selectedUp3Posko,
selectedPosko,
fetchUid,
itemsUid,
itemsUp3,
itemsPosko
} from './reference'
import { onMounted, ref } from 'vue'
const emit = defineEmits(['update:filters'])
const uidPlaceholder = 'Semua Unit Induk Distribusi/Wilayah'
const up3Placeholder = 'Semua Unit Pelaksanaan Pelayanan Pelanggan'
const poskoPlaceholder = 'Semua Posko'
const up3 = ref({ id: 0, name: up3Placeholder })
const uid = ref({ id: 0, name: uidPlaceholder })
const posko = ref({ id: 0, name: poskoPlaceholder })
const data = ref({
uid: uid.value,
up3: up3.value,
posko: posko.value,
periode: '',
minJmlLapor: 1,
maxJmlLapor: 1
})
const setUid = (value: any) => {
uid.value = value
selectedUid(value)
up3.value = { id: 0, name: up3Placeholder }
data.value.uid = value
}
const setUp3 = (value: any) => {
up3.value = value
selectedUp3Posko(value)
posko.value = { id: 0, name: poskoPlaceholder }
data.value.up3 = value
}
const setPosko = (value: any) => {
posko.value = value
selectedPosko(value)
data.value.posko = value
}
onMounted(() => {
fetchUid()
emit('update:filters', data.value)
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit Induk Distribusi/Wilayah:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Induk Distribusi/Wilayah:</label>
<Select placeholder="Semua Unit Induk Distribusi/Wilayah"/>
</div>
<Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" />
</div>
<Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="up3" :placeholder="up3Placeholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Posko:</label>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Posko:</label>
<Select placeholder="Semua Posko" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label>
<Select @update:selected="setPosko($event)" :data="itemsPosko" :selected="posko"
:placeholder="poskoPlaceholder" />
</div>
<DatePicker />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode Tanggal:</label>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Lapor Ulang:</label>
<DatePicker @update:date-value="(value) => (data.periode = value)" />
</div>
<div class="grid grid-flow-col auto-cols-auto gap-x-1.5">
<Select placeholder="1" />
<small class="flex items-center">s/d</small>
<Select placeholder="2" />
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Lapor Ulang:</label>
<div class="flex flex-1 justify-between gap-x-1.5">
<InputNumber :value="data.minJmlLapor" @update:time-value="(value) => (data.minJmlLapor = value)"
class="flex flex-1" />
<small class="flex items-center">s/d</small>
<InputNumber :value="data.maxJmlLapor" @update:time-value="(value) => (data.maxJmlLapor = value)"
class="flex flex-1" />
</div>
</div>
</div>
</template>

190
src/components/Form/FiltersType/Type7.vue Normal file → Executable file
View File

@ -1,47 +1,177 @@
<script setup lang="ts">
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import InputWithSuffix from '../InputWithSuffix.vue';
interface SlaOption {
id: number
name: string
min: string
max: string
}
import Select from '@/components/Select.vue';
import DatePicker from '@/components/DatePicker.vue';
import InputWithSuffix from '../InputWithSuffix.vue';
import {
selectedUid,
selectedUp3Posko,
selectedPosko,
fetchUid,
itemsUid,
itemsUp3,
itemsPosko
} from './reference';
import { onMounted, ref, watch } from 'vue';
const props = defineProps({
slaOptions: {
type: Array as () => SlaOption[],
default: [
{
id: 1,
name: 'Dibawah / Sesuai SLA (<= 45 menit)',
min: '1',
max: '45'
},
{
id: 2,
name: 'Melebihi SLA (> 45 menit)',
min: '46',
max: `${99999 * 60 * 24}`
}
]
}
})
const sla = props.slaOptions.map((item: any) => {
return {
id: item.id,
name: item.name
}
})
const emit = defineEmits(['update:filters'])
const uidPlaceholder = 'Semua Unit Induk Distribusi/Wilayah'
const up3Placeholder = 'Semua Unit Pelaksanaan Pelayanan Pelanggan'
const poskoPlaceholder = 'Semua Posko'
const up3 = ref({ id: 0, name: up3Placeholder })
const uid = ref({ id: 0, name: uidPlaceholder })
const posko = ref({ id: 0, name: poskoPlaceholder })
const isHidden = ref(false)
const totalMin = ref('1 Menit')
const totalMax = ref('5 Menit')
const setDataMin = (value: any) => (totalMin.value = value)
const getDataMin = () => totalMin.value
const setDataMax = (value: any) => (totalMax.value = value)
const getDataMax = () => totalMax.value
const data = ref({
uid: uid.value,
up3: up3.value,
posko: posko.value,
periode: '',
minTime: getDataMin().split(' ')[0],
maxTime: getDataMax().split(' ')[0]
})
const setUid = (value: any) => {
uid.value = value
selectedUid(value)
up3.value = { id: 0, name: up3Placeholder }
data.value.uid = value
}
const setUp3 = (value: any) => {
up3.value = value
selectedUp3Posko(value)
posko.value = { id: 0, name: poskoPlaceholder }
data.value.up3 = value
}
const setPosko = (value: any) => {
posko.value = value
selectedPosko(value)
data.value.posko = value
}
const setMin = (value: any) => {
console.log(value)
data.value.minTime = value
setDataMin(value)
}
const setMax = (value: any) => {
data.value.maxTime = value
setDataMax(value)
}
const triggerInput = ref(false)
const changeDuration = (value: any) => {
if (value.id === 0) {
setMin('1')
setMax('5')
triggerInput.value = false
isHidden.value = false
} else if (value.id === 1) {
setMin(props.slaOptions[0].min)
setMax(props.slaOptions[0].max)
triggerInput.value = true
isHidden.value = true
} else {
setMin(props.slaOptions[1].min)
setMax(props.slaOptions[1].max)
triggerInput.value = true
isHidden.value = true
}
}
watch(data, (newValue) => {
emit('update:filters', newValue)
})
onMounted(() => {
fetchUid()
emit('update:filters', data.value)
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit Induk Distribusi/Wilayah:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Induk Distribusi/Wilayah:</label>
<Select placeholder="Semua Unit Induk Distribusi/Wilayah"/>
</div>
<Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" />
</div>
<Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="up3" :placeholder="up3Placeholder" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Posko:</label>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Posko:</label>
<Select placeholder="Semua Posko" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label>
<Select @update:selected="setPosko($event)" :data="itemsPosko" :selected="posko"
:placeholder="poskoPlaceholder" />
</div>
<DatePicker />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode Tanggal:</label>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Durasi:</label>
<DatePicker @update:date-value="(value) => (data.periode = value)" />
</div>
<div class="flex flex-col gap-y-1">
<Select placeholder="Durasi Menit" />
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Durasi:</label>
<div class="grid grid-flow-col auto-cols-auto gap-x-1.5">
<InputWithSuffix />
<small class="flex items-center">s/d</small>
<InputWithSuffix />
<div class="flex flex-col gap-y-1">
<Select @update:selected="changeDuration($event)" :data="sla" placeholder="Durasi Menit" />
<div class="flex flex-1 justify-between gap-x-1.5" :class="[isHidden ? 'hidden' : '']">
<InputWithSuffix :value="`${data.minTime} Menit`" @update:text="setMin($event)" class="flex flex-1" />
<small class="flex items-center">s/d</small>
<InputWithSuffix :value="`${data.maxTime} Menit`" @update:text="setMax($event)" class="flex flex-1" />
</div>
</div>
</div>
</div>
</template>

75
src/components/Form/FiltersType/Type8.vue Normal file → Executable file
View File

@ -1,26 +1,65 @@
<script setup lang="ts">
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import Select from '@/components/Select.vue';
import DatePicker from '@/components/DatePicker.vue';
import { onMounted, ref, watch } from 'vue';
import { selectedUid, fetchUid, itemsUid, itemsUp3 } from './reference';
const uidPlaceholder = 'Semua Unit Induk Distribusi/Wilayah'
const uppPlaceholder = 'Semua Unit Pelaksanaan Pelayanan Pelanggan'
const poskoPlaceholder = 'Semua Posko'
const uppp = ref({ id: 0, name: uppPlaceholder })
const uid = ref({ id: 0, name: uidPlaceholder })
const posko = ref({ id: 0, name: poskoPlaceholder })
const emit = defineEmits(['update:filters'])
const data = ref({
uid: uid.value,
up3: uppp.value,
posko: posko.value,
periode: ''
})
watch(data.value, (value) => {
emit('update:filters', value)
})
const setUid = (value: any) => {
uid.value = value
selectedUid(value)
uppp.value = { id: 0, name: uppPlaceholder }
data.value.uid = value
}
const setUp3 = (value: any) => {
uppp.value = value
data.value.up3 = value
}
onMounted(() => {
emit('update:filters', data.value)
fetchUid()
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit Induk Distribusi/Wilayah:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Induk Distribusi/Wilayah:</label>
<Select placeholder="Semua Unit Induk Distribusi/Wilayah"/>
<Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
<Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="uppp" :placeholder="uppPlaceholder" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode Tanggal:</label>
<DatePicker @update:date-value="(value) => (data.periode = value)" />
</div>
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label>
<DatePicker />
</div>
</template>

122
src/components/Form/FiltersType/Type9.vue Normal file → Executable file
View File

@ -1,39 +1,99 @@
<script setup lang="ts">
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import InlineRadioGroup from '@/components/Form/InlineRadioGroup.vue'
import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue'
import InlineRadioGroup from '@/components/Form/InlineRadioGroup.vue'
import { onMounted, ref, watch } from 'vue'
import {
selectedUid,
selectedUp3Posko,
selectedPosko,
fetchUid,
itemsUid,
itemsUp3,
itemsPosko
} from './reference'
const uidPlaceholder = 'Semua Unit Induk Distribusi/Wilayah'
const uppPlaceholder = 'Semua Unit Pelaksanaan Pelayanan Pelanggan'
const poskoPlaceholder = 'Semua Posko'
const uppp = ref({ id: 0, name: uppPlaceholder })
const uid = ref({ id: 0, name: uidPlaceholder })
const posko = ref({ id: 0, name: poskoPlaceholder })
const emit = defineEmits(['update:filters'])
const data = ref({
uid: uid.value,
up3: uppp.value,
posko: posko.value,
periode: '',
groupBy: false
})
watch(data.value, (value) => {
emit('update:filters', value)
})
const setUid = (value: any) => {
uid.value = value
selectedUid(value)
uppp.value = { id: 0, name: uppPlaceholder }
data.value.uid = value
}
const setUp3 = (value: any) => {
uppp.value = value
selectedUp3Posko(value)
posko.value = { id: 0, name: poskoPlaceholder }
data.value.up3 = value
}
const setPosko = (value: any) => {
posko.value = value
selectedPosko(value)
data.value.posko = value
}
onMounted(() => {
fetchUid()
emit('update:filters', data.value)
})
</script>
<template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit Induk Distribusi/Wilayah:</label>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Induk Distribusi/Wilayah:</label>
<Select placeholder="Semua Unit Induk Distribusi/Wilayah"/>
<Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
<Select @update:selected="setUp3($event)" :data="itemsUp3" :placeholder="uppPlaceholder" :selected="uppp" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Posko:</label>
<Select @update:selected="setPosko($event)" :data="itemsPosko" :placeholder="poskoPlaceholder"
:selected="posko" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Periode Tanggal:</label>
<DatePicker @update:date-value="(value) => (data.periode = value)" />
</div>
<div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Group By Kode Unit Distribusi:</label>
<InlineRadioGroup @update:group-value="(value) => (data.groupBy = value.id === 2)" :radio-items="[
{ id: 1, title: 'Tidak', checked: true },
{ id: 2, title: 'Ya, Grupkan' }
]" />
</div>
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block"
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Posko:</label>
<Select placeholder="Semua Posko" />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label>
<DatePicker />
</div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Group By Kode Unit Distribusi:</label>
<InlineRadioGroup :radio-items="[{id: 1, title: 'Tidak', checked: true}, {id: 2, title: 'Ya, Grupkan'}]" />
</div>
</template>

1
src/components/Form/FiltersType/index.ts Normal file → Executable file
View File

@ -15,3 +15,4 @@ export { default as Type14 } from '@/components/Form/FiltersType/Type14.vue'
export { default as Type15 } from '@/components/Form/FiltersType/Type15.vue'
export { default as Type16 } from '@/components/Form/FiltersType/Type16.vue'
export { default as Type17 } from '@/components/Form/FiltersType/Type17.vue'
export { default as Type18 } from '@/components/Form/FiltersType/Type18.vue'

View File

@ -0,0 +1,190 @@
import { usePostsStore } from '@/stores/posts'
import { useUlpStore } from '@/stores/ulp'
import { getUid, getUp3, getPosko, getUlp, getRegional, getUidRegional } from '@/utils/api/api.rest'
import { ref } from 'vue'
interface Item {
id: any
name: any
}
const months = [
{ id: 1, name: 'Januari' },
{ id: 2, name: 'Februari' },
{ id: 3, name: 'Maret' },
{ id: 4, name: 'April' },
{ id: 5, name: 'Mei' },
{ id: 6, name: 'Juni' },
{ id: 7, name: 'Juli' },
{ id: 8, name: 'Agustus' },
{ id: 9, name: 'September' },
{ id: 10, name: 'Oktober' },
{ id: 11, name: 'November' },
{ id: 12, name: 'Desember' }
]
// create 4 year back array
const year = new Date().getFullYear()
const years = ref<Item[]>([])
for (let i = 0; i < 5; i++) {
years.value.push({ id: year - i, name: year - i })
}
const itemsUid = ref<Item[]>([])
const itemsUp3 = ref<Item[]>([])
const itemsPosko = ref<Item[]>([])
const itemsUlp = ref<Item[]>([])
const itemsRegional = ref<Item[]>([])
const itemsMedia = ref<Item[]>([])
// Fetch data from the API using Axios
const fetchMedia = () => {
itemsMedia.value = [
{ id: 'Ulasan Aplikasi PLN Mobile', name: 'Ulasan Aplikasi PLN Mobile' },
{ id: 'Twitter', name: 'Twitter' },
{ id: 'PLN Mobile', name: 'PLN Mobile' },
{ id: 'Media Massa', name: 'Media Massa' },
{ id: 'Live Chat Website', name: 'Live Chat Website' },
{ id: 'Live Chat PLN Mobile', name: 'Live Chat PLN Mobile' },
{ id: 'Instagram', name: 'Instagram' },
{ id: 'Facebook', name: 'Facebook' },
{ id: 'Email', name: 'Email' },
{ id: 'EMS', name: 'EMS' },
{ id: 'Datang ke Kantor', name: 'Datang ke Kantor' },
{ id: 'Call ke Kantor Unit', name: 'Call ke Kantor Unit' },
{ id: 'Call PLN 123', name: 'Call PLN 123' }
]
}
const fetchUidByRegional = async (regional: number) => {
if (regional == 0) {
itemsUid.value = []
} else {
try {
const res = await getUidRegional(regional)
itemsUid.value = res.data.map((item: any) => ({
id: item.id,
name: item.nama.toUpperCase()
}))
} catch (error) {
console.error('Error fetching data:', error)
}
}
}
// Fetch data from the API using Axios
const fetchUid = async () => {
try {
const res = await getUid()
itemsUid.value = res.data.map((item: any) => ({
id: item.id,
name: item.nama
}))
} catch (error) {
console.error('Error fetching data:', error)
}
}
const fetchDataUp3 = async (uid: number) => {
if (uid == 0) {
itemsUp3.value = []
itemsUlp.value = []
itemsPosko.value = []
} else {
try {
const res = await getUp3(uid)
itemsUp3.value = res.data.map((item: any) => ({
id: item.id,
name: item.nama
}))
} catch (error) {
console.error('Error fetching data:', error)
}
}
}
const fetchDataUlp = async (up3: number) => {
if (up3 == 0) {
itemsUlp.value = []
} else {
try {
const res = await getUlp(up3)
itemsUlp.value = res.data.map((item: any) => ({
id: item.id,
name: item.nama
}))
} catch (error) {
console.error('Error fetching data:', error)
}
}
}
const fetchDataPosko = async (up3: number) => {
if (up3 == 0) {
itemsPosko.value = []
} else {
try {
const res = await getPosko(up3)
itemsPosko.value = res.data.map((item: any) => ({
id: item.id,
name: item.nama
}))
} catch (error) {
console.error('Error fetching data:', error)
}
}
}
const fetchRegional = async () => {
try {
const res = await getRegional()
itemsRegional.value = res.data.map((item: any) => ({
id: item.id,
name: String(item.nama).toUpperCase()
}))
} catch (error) {
console.error('Error fetching data:', error)
}
}
const formatWaktu = (durasiDetik: number): string => {
const hari = Math.floor(durasiDetik / (3600 * 24))
const sisaDetik = durasiDetik % (3600 * 24)
const jam = Math.floor(sisaDetik / 3600)
const sisaDetik2 = sisaDetik % 3600
const menit = Math.floor(sisaDetik2 / 60)
const detik = sisaDetik2 % 60
return `${hari} - ${jam} : ${menit} : ${detik}`
}
const selectedUid = (value: any) => {
fetchDataUp3(value.id)
}
const selectedUp3Posko = (value: any) => {
if (value.id != 0) {
fetchDataPosko(value.id)
}
}
const selectedUp3Ulp = (value: any) => {
if (value.id != 0) {
fetchDataUlp(value.id)
}
}
const selectedPosko = (value: any) => {
usePostsStore().setData(value.id)
}
const selectedUlp = (value: any) => {
useUlpStore().setData(value.id)
}
export {
selectedUid,
selectedUp3Posko,
selectedUp3Ulp,
selectedPosko,
selectedUlp,
fetchRegional,
fetchUidByRegional,
fetchUid,
fetchMedia,
itemsUid,
itemsUp3,
itemsPosko,
itemsRegional,
itemsMedia,
itemsUlp,
months,
years,
formatWaktu
}

42
src/components/Form/InlineRadioGroup.vue Normal file → Executable file
View File

@ -3,11 +3,19 @@
<fieldset>
<div class="space-y-3 sm:flex sm:items-center sm:space-y-0 sm:space-x-5">
<div v-for="item in radioItems" :key="item.id" class="flex items-center">
<input :id="`${item.id}`" type="radio" name="radio"
:checked="item.hasOwnProperty('checked') && item.checked === true"
class="w-4 h-4 border-gray-300 text-primary-500 peer focus:ring-primary-500" />
<label :for="`${item.id}`" class="block ml-3 text-sm font-medium text-gray-700 peer-checked:text-primary-500">{{
item.title }}</label>
<input
v-model="groupValue"
type="radio"
name="radio"
:checked="itemSelected.id === item.id ? true : false"
@change="onChange(item)"
class="w-4 h-4 border-gray-300 text-primary-500 peer focus:ring-primary-500"
/>
<label
:for="`${item.id}`"
class="block ml-3 text-sm font-medium text-gray-700 peer-checked:text-primary-500"
>{{ item.title }}</label
>
</div>
</div>
</fieldset>
@ -15,18 +23,32 @@
</template>
<script setup lang="ts">
import { type PropType } from 'vue'
import { ref, type PropType, onMounted } from 'vue'
interface Item {
id: number;
title: string;
checked?: boolean;
id: number
title: string
checked?: boolean
}
defineProps({
const onChange = (e: Item) => {
itemSelected.value = e
console.log(e)
emit('update:groupValue', e)
}
const props = defineProps({
radioItems: {
type: Array as PropType<Item[]>,
required: true
}
})
const itemSelected = ref(props.radioItems[0])
const emit = defineEmits(['update:groupValue'])
const groupValue = ref(1)
onMounted(() => {
itemSelected.value = props.radioItems[0]
})
</script>

View File

@ -0,0 +1,43 @@
<script setup lang="ts">
import { ref, watch } from 'vue';
const props = defineProps({
placeholder: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
},
value: {
type: Number,
default: 1
},
class: {
type: String,
default: ''
}
})
const emit = defineEmits(['update:timeValue'])
const timeValue = ref(1)
watch(timeValue, (newValue) => {
emit('update:timeValue', newValue)
})
</script>
<template>
<div class="relative w-full overflow-hidden bg-gray-200 rounded-lg" :class="[props.class]">
<input v-model="timeValue" autocomplete="off" type="number" :placeholder="placeholder" :disabled="disabled"
:readonly="readonly" inputmode="numeric" pattern="[0-9.]*"
onblur="this.value = parseInt(this.value) ? this.value : 1"
oninput="this.value = parseInt(this.value) ? this.value.replace(/[^0-9.]/g, '') : 1"
class="w-full px-4 py-2 text-sm leading-6 text-gray-900 bg-gray-200 border-0 border-transparent rounded-lg placeholder:text-gray-400 outline-0 focus:outline-0 focus:border-0 focus:ring-0" />
</div>
</template>

30
src/components/Form/InputWithFilter.vue Normal file → Executable file
View File

@ -1,10 +1,10 @@
<script setup lang="ts">
import { PhMagnifyingGlass } from '@phosphor-icons/vue';
import { PhMagnifyingGlass } from '@phosphor-icons/vue'
import { type PropType } from 'vue'
interface FilterItems {
id: number;
title: string;
id: number
title: string
}
const props = defineProps({
@ -25,29 +25,43 @@ const props = defineProps({
required: true
}
})
const emit = defineEmits(['update:keyword', 'update:filters'])
const setKeyword = (event: Event) => {
emit('update:keyword', (event.target as HTMLInputElement).value)
}
const setFilter = (event: Event) => {
emit('update:filters', (event.target as HTMLSelectElement).value)
}
</script>
<template>
<div class="relative w-full overflow-hidden rounded-lg">
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
<PhMagnifyingGlass size="18" class="text-gray-900" weight="regular" />
</div>
<input
@input="setKeyword"
:placeholder="placeholder"
:disabled="disabled"
:readonly="readonly"
type="text"
class="w-full px-4 py-2 pl-10 text-sm leading-6 placeholder:text-gray-400 text-gray-900 border-0 border-transparent rounded-lg outline-0 bg-gray-200 focus:outline-0 focus:border-0 focus:ring-0"
class="w-full px-4 py-2 pl-10 text-sm leading-6 text-gray-900 bg-gray-200 border-0 border-transparent rounded-lg placeholder:text-gray-400 outline-0 focus:outline-0 focus:border-0 focus:ring-0"
/>
<div class="absolute inset-y-0 right-0 flex items-center">
<label for="filters" class="sr-only">filters</label>
<span class="block border border-gray-600 h-5"></span>
<span class="block h-5 border border-gray-600"></span>
<select
@change="setFilter"
id="filters"
name="filters"
class="h-full bg-gray-200 text-sm rounded-lg border-transparent py-0 pl-2 pr-7 text-gray-900 focus:outline-0 focus:border-0 focus:ring-0"
class="h-full py-0 pl-2 text-sm text-gray-900 bg-gray-200 border-transparent rounded-lg pr-7 focus:outline-0 focus:border-0 focus:ring-0"
>
<option :key="filter.id" :value="filter.id" v-for="filter in filters">{{ filter.title }}</option>
<option :key="filter.id" :value="filter.id" v-for="filter in filters">
{{ filter.title }}
</option>
</select>
</div>
</div>

80
src/components/Form/InputWithSuffix.vue Normal file → Executable file
View File

@ -1,34 +1,58 @@
<script setup lang="ts">
const props = defineProps({
placeholder: {
type: String,
default: "",
},
disabled: {
type: Boolean,
default: false,
},
readonly: {
type: Boolean,
default: false,
}
})
import { ref, watch } from 'vue';
const props = defineProps({
placeholder: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
},
value: {
type: String,
default: '1 Menit'
},
class: {
type: String,
default: ''
}
})
const handleInput = (e: any) => {
e.target.value = e.target.value.replace(/[^0-9.]/g, '')
}
const handleBlur = (e: any) => {
e.target.value = e.target.value ? e.target.value + ' Menit' : ''
}
const handleFocus = (e: any) => {
e.target.value = e.target.value.replace(/[^0-9.]/g, '')
}
const emit = defineEmits(['update:text'])
const text = ref(props.value)
watch(text, (val) => {
const validatedText = val.replace(/[^0-9.]/g, '')
if (parseInt(validatedText)) {
emit('update:text', validatedText)
}
})
</script>
<template>
<div class="relative w-full overflow-hidden rounded-lg bg-gray-200">
<input
autocomplete="off"
type="text"
:placeholder="placeholder"
:disabled="disabled"
:readonly="readonly"
inputmode="numeric"
pattern="[0-9.]*"
oninput="this.value = this.value.replace(/[^0-9.]/g, '')"
onblur="this.value = this.value ? this.value + ' Menit' : ''"
onfocus="this.value = this.value.replace(/[^0-9.]/g, '')"
class="w-full px-4 py-2 text-sm leading-6 placeholder:text-gray-400 text-gray-900 border-0 border-transparent rounded-lg outline-0 bg-gray-200 focus:outline-0 focus:border-0 focus:ring-0"
/>
<div class="relative w-full overflow-hidden bg-gray-200 rounded-lg" :class="[props.class]">
<input v-model="text" autocomplete="off" type="text" :placeholder="placeholder" :readonly="readonly"
inputmode="numeric" pattern="[0-9.]*" :disabled="disabled" @input="handleInput($event)" @blur="handleBlur($event)"
@focus="handleFocus($event)"
class="w-full px-4 py-2 text-sm leading-6 text-gray-900 bg-gray-200 border-0 border-transparent rounded-lg placeholder:text-gray-400 outline-0 focus:outline-0 focus:border-0 focus:ring-0" />
</div>
</template>

0
src/components/Input.vue Normal file → Executable file
View File

85
src/components/InputText.vue Normal file → Executable file
View File

@ -1,59 +1,62 @@
<script setup lang="ts">
import { ref } from 'vue'
import { ref } from 'vue';
const props = defineProps({
type: {
type: String,
default: "text",
},
placeholder: {
type: String,
default: "",
},
value: {
type: String,
default: "",
},
disabled: {
type: Boolean,
default: false,
},
readonly: {
type: Boolean,
default: false,
},
className: {
type: String,
default: "",
}
type: {
type: String,
default: 'text'
},
placeholder: {
type: String,
default: ''
},
value: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
},
className: {
type: String,
default: ''
}
})
const emit = defineEmits(['update:value'])
const updateValue = (event: Event) => {
const value = (event.target as HTMLInputElement).value;
emit('update:value', value)
const value = (event.target as HTMLInputElement).value
emit('update:value', value)
}
const inputType = ref(props.type)
const switchInputType = () => {
inputType.value = inputType.value == 'password' ? 'text' : 'password'
inputType.value = inputType.value == 'password' ? 'text' : 'password'
}
</script>
<template>
<div :class="['relative w-full overflow-hidden rounded-lg bg-gray-50 ', className]">
<input autocomplete="off" :type="inputType" :placeholder="placeholder" :value="value" @input="updateValue($event)"
:disabled="disabled" :readonly="readonly"
:class="['w-full px-4 py-2 text-sm leading-6 placeholder:text-gray-400 text-gray-900 border-0 border-transparent rounded-lg outline-0 bg-gray-200 focus:outline-0 focus:border-0 focus:ring-0']" />
<div :class="['relative w-full overflow-hidden rounded-lg bg-gray-200 ', className]">
<input v-if="!readonly" autocomplete="off" :type="inputType" :placeholder="placeholder" :value="value"
@input="updateValue($event)" :disabled="disabled" :readonly="readonly" :class="[
'w-full px-4 py-2 text-sm leading-6 placeholder:text-gray-400 text-gray-900 border-0 border-transparent rounded-lg outline-0 bg-gray-200 focus:outline-0 focus:border-0 focus:ring-0'
]" />
<p v-else
class="px-4 py-2 text-sm leading-6 text-gray-900 bg-gray-200 border-0 border-transparent rounded-lg outline-0 min-h-[40px]">
{{ value && value.length < 1 && value.trim() === '' ? '-' : value }} </p>
<span @click="switchInputType" v-if="type == 'password'"
class="absolute top-0 bottom-0 right-0 mx-3 my-auto cursor-pointer h-fit">
<svg width="20" height="20" viewBox="0 0 20 20"
:class="[inputType == 'password' ? 'fill-gray-500' : 'fill-primary-500']">
<path
d="M19.3211 9.74688C19.2937 9.68516 18.632 8.21719 17.1609 6.74609C15.2008 4.78594 12.725 3.75 9.99999 3.75C7.27499 3.75 4.79921 4.78594 2.83905 6.74609C1.36796 8.21719 0.703118 9.6875 0.678899 9.74688C0.643362 9.82681 0.625 9.91331 0.625 10.0008C0.625 10.0883 0.643362 10.1748 0.678899 10.2547C0.706243 10.3164 1.36796 11.7836 2.83905 13.2547C4.79921 15.2141 7.27499 16.25 9.99999 16.25C12.725 16.25 15.2008 15.2141 17.1609 13.2547C18.632 11.7836 19.2937 10.3164 19.3211 10.2547C19.3566 10.1748 19.375 10.0883 19.375 10.0008C19.375 9.91331 19.3566 9.82681 19.3211 9.74688ZM9.99999 15C7.5953 15 5.49452 14.1258 3.75546 12.4023C3.0419 11.6927 2.43483 10.8836 1.95312 10C2.4347 9.11636 3.04179 8.30717 3.75546 7.59766C5.49452 5.87422 7.5953 5 9.99999 5C12.4047 5 14.5055 5.87422 16.2445 7.59766C16.9595 8.307 17.5679 9.11619 18.0508 10C17.4875 11.0516 15.0336 15 9.99999 15ZM9.99999 6.25C9.25831 6.25 8.53329 6.46993 7.9166 6.88199C7.29992 7.29404 6.81927 7.87971 6.53544 8.56494C6.25162 9.25016 6.17735 10.0042 6.32205 10.7316C6.46674 11.459 6.82389 12.1272 7.34834 12.6517C7.87279 13.1761 8.54097 13.5333 9.2684 13.6779C9.99583 13.8226 10.7498 13.7484 11.4351 13.4645C12.1203 13.1807 12.7059 12.7001 13.118 12.0834C13.5301 11.4667 13.75 10.7417 13.75 10C13.749 9.00576 13.3535 8.05253 12.6505 7.34949C11.9475 6.64645 10.9942 6.25103 9.99999 6.25ZM9.99999 12.5C9.50554 12.5 9.02219 12.3534 8.61107 12.0787C8.19994 11.804 7.87951 11.4135 7.69029 10.9567C7.50107 10.4999 7.45157 9.99723 7.54803 9.51227C7.64449 9.02732 7.88259 8.58186 8.23222 8.23223C8.58186 7.8826 9.02731 7.6445 9.51227 7.54804C9.99722 7.45157 10.4999 7.50108 10.9567 7.6903C11.4135 7.87952 11.804 8.19995 12.0787 8.61107C12.3534 9.0222 12.5 9.50555 12.5 10C12.5 10.663 12.2366 11.2989 11.7678 11.7678C11.2989 12.2366 10.663 12.5 9.99999 12.5Z" />
</svg>
class="absolute top-0 bottom-0 right-0 mx-3 my-auto cursor-pointer h-fit">
<svg width="20" height="20" viewBox="0 0 20 20"
:class="[inputType == 'password' ? 'fill-gray-500' : 'fill-primary-500']">
<path
d="M19.3211 9.74688C19.2937 9.68516 18.632 8.21719 17.1609 6.74609C15.2008 4.78594 12.725 3.75 9.99999 3.75C7.27499 3.75 4.79921 4.78594 2.83905 6.74609C1.36796 8.21719 0.703118 9.6875 0.678899 9.74688C0.643362 9.82681 0.625 9.91331 0.625 10.0008C0.625 10.0883 0.643362 10.1748 0.678899 10.2547C0.706243 10.3164 1.36796 11.7836 2.83905 13.2547C4.79921 15.2141 7.27499 16.25 9.99999 16.25C12.725 16.25 15.2008 15.2141 17.1609 13.2547C18.632 11.7836 19.2937 10.3164 19.3211 10.2547C19.3566 10.1748 19.375 10.0883 19.375 10.0008C19.375 9.91331 19.3566 9.82681 19.3211 9.74688ZM9.99999 15C7.5953 15 5.49452 14.1258 3.75546 12.4023C3.0419 11.6927 2.43483 10.8836 1.95312 10C2.4347 9.11636 3.04179 8.30717 3.75546 7.59766C5.49452 5.87422 7.5953 5 9.99999 5C12.4047 5 14.5055 5.87422 16.2445 7.59766C16.9595 8.307 17.5679 9.11619 18.0508 10C17.4875 11.0516 15.0336 15 9.99999 15ZM9.99999 6.25C9.25831 6.25 8.53329 6.46993 7.9166 6.88199C7.29992 7.29404 6.81927 7.87971 6.53544 8.56494C6.25162 9.25016 6.17735 10.0042 6.32205 10.7316C6.46674 11.459 6.82389 12.1272 7.34834 12.6517C7.87279 13.1761 8.54097 13.5333 9.2684 13.6779C9.99583 13.8226 10.7498 13.7484 11.4351 13.4645C12.1203 13.1807 12.7059 12.7001 13.118 12.0834C13.5301 11.4667 13.75 10.7417 13.75 10C13.749 9.00576 13.3535 8.05253 12.6505 7.34949C11.9475 6.64645 10.9942 6.25103 9.99999 6.25ZM9.99999 12.5C9.50554 12.5 9.02219 12.3534 8.61107 12.0787C8.19994 11.804 7.87951 11.4135 7.69029 10.9567C7.50107 10.4999 7.45157 9.99723 7.54803 9.51227C7.64449 9.02732 7.88259 8.58186 8.23222 8.23223C8.58186 7.8826 9.02731 7.6445 9.51227 7.54804C9.99722 7.45157 10.4999 7.50108 10.9567 7.6903C11.4135 7.87952 11.804 8.19995 12.0787 8.61107C12.3534 9.0222 12.5 9.50555 12.5 10C12.5 10.663 12.2366 11.2989 11.7678 11.7678C11.2989 12.2366 10.663 12.5 9.99999 12.5Z" />
</svg>
</span>
</div>
</template>
</div>
</template>

4
src/components/Navigation/Aside/Aside.vue Normal file → Executable file
View File

@ -35,7 +35,7 @@ const closeSideBar = () => menu.toggleSidebar()
<template>
<TransitionRoot as="template" :show="menu.sidebarOpen">
<Dialog as="div" class="relative z-40 md:hidden" @close="closeSideBar">
<Dialog as="div" class="relative z-40 lg:hidden" @close="closeSideBar">
<TransitionChild as="template" enter="transition-opacity ease-linear duration-300" enter-from="opacity-0"
enter-to="opacity-100" leave="transition-opacity ease-linear duration-300" leave-from="opacity-100"
leave-to="opacity-0">
@ -86,7 +86,7 @@ const closeSideBar = () => menu.toggleSidebar()
</Dialog>
</TransitionRoot>
<!-- Static sidebar for desktop -->
<div class="z-10 hidden md:fixed md:inset-y-0 md:flex md:w-80 md:flex-col">
<div class="z-10 hidden lg:fixed lg:inset-y-0 lg:flex lg:w-80 lg:flex-col">
<!-- Sidebar component, swap this element with another sidebar if you like -->
<div class="flex flex-row items-center flex-shrink-0 h-16 px-2 bg-primary-50">
<button type="button"

2
src/components/Navigation/Aside/AsideMenuMultiple.vue Normal file → Executable file
View File

@ -43,7 +43,7 @@ const isMenuSelected = computed(() => {
:class="[(isMenuSelected || item.expanded || isChildren || selected) ? ' fill-primary-500' : 'text-aside group-hover:fill-primary-500', 'mr-2 flex-shrink-0 h-6 w-6']"
aria-hidden="true" />
<span
:class="[(isMenuSelected || item.expanded || selected) ? 'text-primary-500' : 'group-hover:text-primary-500', 'flex-1']">
:class="[(isMenuSelected || item.expanded || selected) ? 'text-primary-500' : 'group-hover:text-primary-500', 'flex-1 aside-text']">
{{ item.name }}
</span>

0
src/components/Navigation/Aside/AsideMenuSingle.vue Normal file → Executable file
View File

157
src/components/Navigation/Header.vue Normal file → Executable file
View File

@ -1,15 +1,9 @@
<script setup lang="ts">
import { useAuthStore } from '@/stores/auth'
import { useUserStore } from '@/stores/user'
import { useCommandPalattesStore } from '@/stores/command'
import { useMenuStore } from '@/stores/menu'
import {
Menu,
MenuButton,
MenuItem,
MenuItems,
} from '@headlessui/vue'
import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/vue'
import { MagnifyingGlassIcon } from '@heroicons/vue/24/solid'
import PictureInitial from '@/components/PictureInitial.vue'
import { useDialogStore } from '@/stores/dialog'
@ -25,85 +19,84 @@ const dialog = useDialogStore()
const openSideBar = () => menu.toggleSidebar()
const showDialogLogout = () => {
dialog.type = 'error'
dialog.title = 'Logout dari akun?'
dialog.content = 'Apakah Anda sudah yakin akan logout dari akun ini?'
dialog.cancelText = 'Batalkan'
dialog.confirmText = 'Ya, logout'
dialog.showCancelButton = true
dialog.onConfirm = () => {
auth.logout()
window.location.href = '/login'
}
dialog.open = true
dialog.type = 'error'
dialog.title = 'Logout dari akun?'
dialog.content = 'Apakah Anda sudah yakin akan logout dari akun ini?'
dialog.cancelText = 'Batalkan'
dialog.confirmText = 'Ya, logout'
dialog.showCancelButton = true
dialog.onConfirm = () => {
auth.logout()
window.location.href = '/login'
}
dialog.open = true
}
</script>
<template>
<div class="sticky top-0 z-10 flex flex-shrink-0 h-16 bg-primary-50 md:ml-80">
<button type="button" class="px-4 text-gray-500 focus:outline-none focus:ring-0 md:hidden" @click="openSideBar">
<span class="sr-only">Open sidebar</span>
<IconBars3 class="w-6 h-6 fill-gray-600" />
<div class="sticky top-0 z-10 flex flex-shrink-0 h-16 bg-primary-50 lg:ml-80">
<button type="button" class="px-4 text-gray-500 focus:outline-none focus:ring-0 lg:hidden" @click="openSideBar">
<span class="sr-only">Open sidebar</span>
<IconBars3 class="w-6 h-6 fill-gray-600" />
</button>
<RouterLink to="/home" class="flex items-center flex-shrink-0 my-auto ml-2 lg:hidden">
<img class="w-auto h-11" :src="IconApp" alt="PLN" />
</RouterLink>
<div class="flex justify-end w-full px-4">
<div class="flex items-center ml-4 md:ml-6">
<button @click="command.showCommandPalettes" type="button"
class="flex flex-row items-center md:w-[300px] p-2 mr-2 text-gray-400 bg-white rounded-full hover:text-primary-500 focus:outline-none focus:ring-0">
<span class="sr-only">Search</span>
<MagnifyingGlassIcon class="w-6 h-6 text-primary-500" aria-hidden="true" />
<span class="hidden px-3 text-sm font-medium text-gray-500 md:block text-md">Cari menu</span>
</button>
<RouterLink to="/home" class="flex items-center flex-shrink-0 my-auto ml-2 md:hidden">
<img class="w-auto h-11" :src="IconApp" alt="PLN" />
</RouterLink>
<div class="flex justify-end w-full px-4">
<div class="flex items-center ml-4 md:ml-6">
<button @click="command.showCommandPalettes" type="button"
class="flex flex-row items-center md:w-[300px] p-2 mr-2 text-gray-400 bg-white rounded-full hover:text-primary-500 focus:outline-none focus:ring-0">
<span class="sr-only">Search</span>
<MagnifyingGlassIcon class="w-6 h-6 text-primary-500" aria-hidden="true" />
<span class="hidden px-3 text-sm font-medium text-gray-500 md:block text-md">Cari menu</span>
</button>
<!-- Profile dropdown -->
<Menu as="div" class="relative ml-1">
<div>
<MenuButton
class="flex items-center max-w-xs px-1 py-1 text-sm rounded-full bg-secondary-100 md:bg-primary-500 focus:outline-none focus:ring-0 line-clamp-1">
<span class="sr-only">Open user menu</span>
<PictureInitial size-class="w-8 h-8" background-class="bg-secondary-100"
font-class="text-xs font-bold text-primary-500" :name="user.user_name" />
<span class="hidden px-3 text-xs font-medium md:block text-primary-50 line-clamp-1">
{{ user.user_name }}
</span>
</MenuButton>
</div>
<transition enter-active-class="transition duration-100 ease-out"
enter-from-class="transform scale-95 opacity-0" enter-to-class="transform scale-100 opacity-100"
leave-active-class="transition duration-75 ease-in"
leave-from-class="transform scale-100 opacity-100" leave-to-class="transform scale-95 opacity-0">
<MenuItems class="container-menu-item">
<div class="container-menu-profile group">
<div class="flex items-center">
<div>
<PictureInitial class-name="inline-block" size-class="w-9 h-9"
background-class="bg-secondary-100"
font-class="text-xs font-normal font-semibold text-primary-500"
:name="user.user_name" />
</div>
<div class="ml-3 space-y-1">
<p class="text-sm font-medium text-primary-50 ">
{{ user.user_name }}
</p>
<p class="text-xs font-normal text-primary-50">
{{ user.user_access }}
</p>
</div>
</div>
</div>
<MenuItem v-slot="{ active }">
<button @click="showDialogLogout" :class="[active ? 'menu-item-active' : 'menu-item']">
Log out
</button>
</MenuItem>
</MenuItems>
</transition>
</Menu>
</div>
</div>
<!-- Profile dropdown -->
<Menu as="div" class="relative ml-1">
<div>
<MenuButton
class="flex items-center max-w-xs px-1 py-1 text-sm rounded-full bg-secondary-100 md:bg-primary-500 focus:outline-none focus:ring-0 line-clamp-1">
<span class="sr-only">Open user menu</span>
<PictureInitial size-class="w-8 h-8" background-class="bg-secondary-100"
font-class="text-xs font-bold text-primary-500" :name="user.user_name" />
<span class="hidden px-3 text-xs font-medium md:block text-primary-50 line-clamp-1">
{{ user.user_name }}
</span>
</MenuButton>
</div>
<transition enter-active-class="transition duration-100 ease-out"
enter-from-class="transform scale-95 opacity-0" enter-to-class="transform scale-100 opacity-100"
leave-active-class="transition duration-75 ease-in" leave-from-class="transform scale-100 opacity-100"
leave-to-class="transform scale-95 opacity-0">
<MenuItems class="container-menu-item">
<div class="container-menu-profile group">
<div class="flex items-center">
<div>
<PictureInitial class-name="inline-block" size-class="w-9 h-9" background-class="bg-secondary-100"
font-class="text-xs font-normal font-semibold text-primary-500" :name="user.user_name" />
</div>
<div class="ml-3 space-y-1">
<p class="text-sm font-medium text-primary-50">
{{ user.user_name }}
</p>
<p class="text-xs font-normal text-primary-50">
{{ user.user_access }}
</p>
<p class="text-xs font-normal border-t border-white text-primary-50">
UID {{ user.user_uid }}
</p>
</div>
</div>
</div>
<MenuItem v-slot="{ active }">
<button @click="showDialogLogout" :class="[active ? 'menu-item-active' : 'menu-item']">
Log out
</button>
</MenuItem>
</MenuItems>
</transition>
</Menu>
</div>
</div>
</template>
</div>
</template>

0
src/components/Navigation/Navigation.vue Normal file → Executable file
View File

0
src/components/Notification/Notification.vue Normal file → Executable file
View File

0
src/components/Notification/NotificationProvider.vue Normal file → Executable file
View File

0
src/components/Notification/icons/CloseIcon.vue Normal file → Executable file
View File

0
src/components/Notification/icons/ErrorIcon.vue Normal file → Executable file
View File

0
src/components/Notification/icons/InfoIcon.vue Normal file → Executable file
View File

0
src/components/Notification/icons/SuccessIcon.vue Normal file → Executable file
View File

0
src/components/Notification/icons/WarningIcon.vue Normal file → Executable file
View File

0
src/components/Notification/icons/index.ts Normal file → Executable file
View File

0
src/components/Notification/index.ts Normal file → Executable file
View File

View File

View File

View File

0
src/components/Notification/interfaces/index.ts Normal file → Executable file
View File

0
src/components/Notification/store/index.ts Normal file → Executable file
View File

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,240 @@
<template>
<div class="mt-4 lg:mt-6 max-w-7xl">
<h1 class="text-xl font-medium md:text-2xl text-dark">Laporan Pengaduan PLN Mobile</h1>
</div>
<DxDataGrid
class="max-h-[calc(100vh-140px)] mb-10"
:data-source="data"
:show-column-lines="true"
:show-row-lines="false"
:show-borders="true"
:row-alternation-enabled="true"
:hover-state-enabled="true"
@selection-changed="onDataSelectionChanged"
@exporting="onExporting"
:allow-column-resizing="true"
column-resizing-mode="widget"
:word-wrap-enabled="true"
>
<DxSelection mode="single" />
<DxPaging :enabled="false" />
<DxScrolling column-rendering-mode="virtual" mode="virtual" />
<DxSearchPanel :visible="true" :highlight-case-sensitive="true" />
<DxExport
:enabled="true"
:formats="['pdf', 'xlsx', 'document']"
:allow-export-selected-data="false"
/>
<DxColumnFixing :enabled="true" />
<DxColumn
alignment="center"
data-field="nama_ulp"
caption="Nama Unit"
css-class="custom-table-column"
cell-template="formatText"
/>
<DxColumn
:width="170"
alignment="center"
data-field=""
caption="Nama Petugas"
css-class="custom-table-column"
cell-template="formatText"
/>
<DxColumn alignment="center" caption="Total WO" css-class="custom-table-column">
<DxColumn
alignment="center"
caption="(PLN Mobile, CC123, DLL)"
css-class="custom-table-column"
>
<DxColumn
:width="150"
alignment="center"
data-field=""
data-type="number"
caption="a"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
</DxColumn>
<DxColumn
alignment="center"
caption="Total Pengaduan Yang Diselesaikan Secara Anomali"
css-class="custom-table-column"
>
<DxColumn alignment="center" caption="PLN Mobile" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="anomali_pln_mobile_marking"
data-type="number"
caption="b"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
<DxColumn alignment="center" caption="CC 123" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="anomali_cc123_marking"
data-type="number"
caption="c"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
<DxColumn alignment="center" caption="Total" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="total_anomali_marking"
data-type="number"
caption="d=b+c"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
</DxColumn>
<DxColumn
alignment="center"
caption="% Pengaduan Yang Diselesaikan Secara Anomali"
css-class="custom-table-column"
>
<DxColumn alignment="center" caption="PLN Mobile" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="persen_anomali_pln_mobile_marking"
data-type="number"
caption="e=b/a"
css-class="custom-table-column"
cell-template="formatPercentage"
/>
</DxColumn>
<DxColumn alignment="center" caption="CC 123" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="persen_anomali_cc123_marking"
data-type="number"
caption="f=c/a"
css-class="custom-table-column"
cell-template="formatPercentage"
/>
</DxColumn>
<DxColumn alignment="center" caption="Total" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="persen_anomali_marking"
data-type="number"
caption="g=e+f"
css-class="custom-table-column"
cell-template="formatPercentage"
/>
</DxColumn>
</DxColumn>
<template #formatNumber="{ data }">
<p class="text-right cursor-pointer" @click="showData()">
{{
isNumber(data.text)
? data.column.caption == '%'
? formatPercentage(data.text)
: formatNumber(data.text)
: data.text
}}
</p>
</template>
<template #formatPercentage="{ data }">
<p class="text-right cursor-pointer" @click="showData()">
{{ isNumber(data.text) ? formatPercentage(data.text) : data.text }}
</p>
</template>
<template #formatText="{ data }">
<p class="text-left cursor-pointer" @click="showData()">
{{ data.text }}
</p>
</template>
<template #formatTime="{ data }" @click="showData()">
<p class="!text-right">
{{ parseInt(data.text) ? formatWaktu(data.text) : '-' }}
</p>
</template>
</DxDataGrid>
</template>
<script setup lang="ts">
import { DxDataGrid } from 'devextreme-vue'
import {
DxColumn,
DxColumnFixing,
DxExport,
DxPaging,
DxScrolling,
DxSearchPanel,
DxSelection
} from 'devextreme-vue/data-grid'
import { jsPDF } from 'jspdf'
import { exportDataGrid as exportToPdf } from 'devextreme/pdf_exporter'
import { exportDataGrid as exportToExcel } from 'devextreme/excel_exporter'
import { saveAs } from 'file-saver'
import { Workbook } from 'exceljs'
import { computed, ref } from 'vue'
import { formatNumber, formatPercentage, isNumber } from '@/utils/numbers'
import { formatWaktu } from '@/components/Form/FiltersType/reference'
const props = defineProps({
data: Array as () => any[]
})
const data = computed(() => props.data)
const dataSub = ref([])
const dataSelected = ref({})
const dataSubSelected = ref({})
const showDetail = ref(false)
const showData = () => {
showDetail.value = true
}
const closeDetail = () => {
showDetail.value = false
}
const onExporting = (e: any) => {
if (e.format === 'pdf') {
const doc = new jsPDF()
exportToPdf({
jsPDFDocument: doc,
component: e.component,
indent: 5
}).then(() => {
doc.save(`.pdf`)
})
} else {
const workbook = new Workbook()
const worksheet = workbook.addWorksheet('Employees')
exportToExcel({
component: e.component,
worksheet,
autoFilterEnabled: true
}).then(() => {
workbook.xlsx.writeBuffer().then((buffer: any) => {
saveAs(new Blob([buffer], { type: 'application/octet-stream' }), 'DataGrid.xlsx')
})
})
e.cancel = true
}
}
const onDataSelectionChanged = ({ selectedRowsData }: any) => {
const dataSelected = selectedRowsData[0]
console.log(data)
}
</script>

View File

@ -0,0 +1,432 @@
<template>
<div class="mt-4 lg:mt-6 max-w-7xl">
<h1 class="text-xl font-medium md:text-2xl text-dark">Laporan Pengaduan Total</h1>
</div>
<DxDataGrid
class="max-h-[calc(100vh-140px)] mb-10"
:show-column-lines="true"
:show-row-lines="false"
:show-borders="true"
:row-alternation-enabled="true"
:hover-state-enabled="true"
@selection-changed="onDataSelectionChanged"
:column-width="100"
@exporting="onExporting"
:allow-column-resizing="true"
column-resizing-mode="widget"
:word-wrap-enabled="true"
:data-source="data"
>
<DxSelection mode="single" />
<DxPaging :enabled="false" />
<DxScrolling column-rendering-mode="virtual" mode="virtual" />
<DxLoadPanel
:position="position"
:show-indicator="showIndicator"
:show-pane="showPane"
:shading="shading"
v-if="loading"
v-model:visible="loading"
:enabled="true"
/>
<DxSearchPanel :visible="true" :highlight-case-sensitive="true" />
<DxExport
:enabled="true"
:formats="['pdf', 'xlsx', 'document']"
:allow-export-selected-data="false"
/>
<DxColumnFixing :enabled="true" />
<DxColumn
:width="170"
alignment="center"
data-field="nama_ulp"
caption="Nama Unit"
css-class="custom-table-column"
cell-template="formatText"
/>
<DxColumn
:width="170"
alignment="center"
data-field="nama_ulp"
caption="Nama Unit"
css-class="custom-table-column"
cell-template="formatText"
name="namaUnit"
:group-index="0"
/>
<DxColumn alignment="center" caption="Total Petugas" css-class="custom-table-column">
<DxColumn
:width="170"
alignment="center"
data-field="total_petugas"
caption="a"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
<DxColumn
alignment="center"
caption="Total Petugas Yang Pengaduan Diselesaikan Secara Anomali"
css-class="custom-table-column"
>
<DxColumn alignment="center" caption="PLN Mobile" css-class="custom-table-column">
<DxColumn alignment="center" caption="b" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="anomali_pln_mobile_marking"
data-type="number"
caption="Marking"
css-class="custom-table-column"
cell-template="formatNumber"
/>
<DxColumn
:width="150"
alignment="center"
data-field="anomali_pln_mobile_non_marking"
data-type="number"
caption="Non Marking"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
</DxColumn>
<DxColumn alignment="center" caption="CC 123" css-class="custom-table-column">
<DxColumn alignment="center" caption="c" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="anomali_cc123_marking"
data-type="number"
caption="Marking"
css-class="custom-table-column"
cell-template="formatNumber"
/>
<DxColumn
:width="150"
alignment="center"
data-field="anomali_cc123_non_marking"
data-type="number"
caption="Non Marking"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
</DxColumn>
<DxColumn alignment="center" caption="Total" css-class="custom-table-column">
<DxColumn alignment="center" caption="d=b+c" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="total_anomali_marking"
data-type="number"
caption="Marking"
css-class="custom-table-column"
cell-template="formatNumber"
/>
<DxColumn
:width="150"
alignment="center"
data-field="total_anomali_non_marking"
data-type="number"
caption="Non Marking"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
</DxColumn>
</DxColumn>
<DxColumn
alignment="center"
caption="% Petugas Yang Pengaduan Diselesaikan Secara Anomali"
css-class="custom-table-column"
>
<DxColumn alignment="center" caption="PLN Mobile" css-class="custom-table-column">
<DxColumn alignment="center" caption="e=b/a" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="persen_anomali_pln_mobile_marking"
data-type="number"
caption="Marking"
css-class="custom-table-column"
cell-template="formatPercentage"
/>
<DxColumn
:width="150"
alignment="center"
data-field="persen_anomali_pln_mobile_non_marking"
data-type="number"
caption="Non Marking"
css-class="custom-table-column"
cell-template="formatPercentage"
/>
</DxColumn>
</DxColumn>
<DxColumn alignment="center" caption="CC 123" css-class="custom-table-column">
<DxColumn alignment="center" caption="f=c/a" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="persen_anomali_cc123_marking"
data-type="number"
caption="Marking"
css-class="custom-table-column"
cell-template="formatPercentage"
/>
<DxColumn
:width="150"
alignment="center"
data-field="persen_anomali_cc123_non_marking"
data-type="number"
caption="Non Marking"
css-class="custom-table-column"
cell-template="formatPercentage"
/>
</DxColumn>
</DxColumn>
<DxColumn alignment="center" caption="Total" css-class="custom-table-column">
<DxColumn alignment="center" caption="g=e+f" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="persen_anomali_marking"
data-type="number"
caption="Marking"
css-class="custom-table-column"
cell-template="formatPercentage"
/>
<DxColumn
:width="150"
alignment="center"
data-field="persen_anomali_non_marking"
data-type="number"
caption="Non Marking"
css-class="custom-table-column"
cell-template="formatPercentage"
/>
</DxColumn>
</DxColumn>
</DxColumn>
<template #formatNumber="{ data }">
<p class="text-right cursor-pointer" @click="showData()">
{{
isNumber(data.text)
? data.column.caption == '%'
? formatPercentage(data.text)
: formatNumber(data.text)
: data.text
}}
</p>
</template>
<template #formatPercentage="{ data }">
<p class="text-right cursor-pointer" @click="showData()">
{{ isNumber(data.text) ? formatPercentage(data.text) : data.text }}
</p>
</template>
<template #formatText="{ data }">
<p class="text-left cursor-pointer" @click="showData()">
{{ data.text }}
</p>
</template>
<template #formatTime="{ data }" @click="showData()">
<p class="!text-right">
{{ parseInt(data.text) ? formatWaktu(data.text) : '-' }}
</p>
</template>
<DxSummary>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="total_petugas"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="anomali_pln_mobile_marking"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="anomali_pln_mobile_non_marking"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="anomali_cc123_marking"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="anomali_cc123_non_marking"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="total_anomali_marking"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="total_anomali_non_marking"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="persen_anomali_pln_mobile_marking"
summary-type="avg"
css-class="!text-right"
:customize-text="(e: any) => formatPercentage(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="persen_anomali_pln_mobile_non_marking"
summary-type="avg"
css-class="!text-right"
:customize-text="(e: any) => formatPercentage(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="persen_anomali_cc123_marking"
summary-type="avg"
css-class="!text-right"
:customize-text="(e: any) => formatPercentage(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="persen_anomali_cc123_non_marking"
summary-type="avg"
css-class="!text-right"
:customize-text="(e: any) => formatPercentage(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="persen_anomali_marking"
summary-type="avg"
css-class="!text-right"
:customize-text="(e: any) => formatPercentage(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="persen_anomali_non_marking"
summary-type="avg"
css-class="!text-right"
:customize-text="(e: any) => formatPercentage(parseFloat(e.value.toString()))"
/>
</DxSummary>
</DxDataGrid>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { DxDataGrid } from 'devextreme-vue'
import {
DxColumn,
DxColumnFixing,
DxExport,
DxGroupItem,
DxLoadPanel,
DxPaging,
DxScrolling,
DxSearchPanel,
DxSelection,
DxSummary
} from 'devextreme-vue/data-grid'
import { jsPDF } from 'jspdf'
import { exportDataGrid as exportToPdf } from 'devextreme/pdf_exporter'
import { exportDataGrid as exportToExcel } from 'devextreme/excel_exporter'
import { saveAs } from 'file-saver'
import { Workbook } from 'exceljs'
import { formatNumber, formatPercentage, isNumber } from '@/utils/numbers'
import { formatWaktu } from '@/components/Form/FiltersType/reference'
const position = { of: '#data' }
const showIndicator = ref(true)
const shading = ref(true)
const showPane = ref(true)
const props = defineProps({
data: Array as () => any[],
loading: {
type: Boolean,
default: false
}
})
const data = computed(() => props.data)
const dataSub = ref<any[]>([])
const dataSelected = ref<any>({})
const dataSubSelected = ref<any>({})
const showDetail = ref(false)
const showData = () => {
showDetail.value = true
}
const closeDetail = () => {
showDetail.value = false
}
const loading = ref(computed(() => props.loading))
const onExporting = (e: any) => {
if (e.format === 'pdf') {
const doc = new jsPDF()
exportToPdf({
jsPDFDocument: doc,
component: e.component,
indent: 5
}).then(() => {
doc.save(`.pdf`)
})
} else {
const workbook = new Workbook()
const worksheet = workbook.addWorksheet('Employees')
exportToExcel({
component: e.component,
worksheet,
autoFilterEnabled: true
}).then(() => {
workbook.xlsx.writeBuffer().then((buffer: any) => {
saveAs(new Blob([buffer], { type: 'application/octet-stream' }), 'DataGrid.xlsx')
})
})
e.cancel = true
}
}
const onDataSelectionChanged = ({ selectedRowsData }: any) => {
dataSelected.value = selectedRowsData[0]
console.log(data)
}
</script>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,178 @@
<template>
<div class="mt-4 lg:mt-6 max-w-7xl">
<h1 class="text-xl font-medium md:text-2xl text-dark">Laporan Pengaduan PLN Mobile</h1>
</div>
<DxDataGrid
class="max-h-[calc(100vh-140px)] mb-10"
:data-source="data"
:show-column-lines="true"
:show-row-lines="false"
:show-borders="true"
:row-alternation-enabled="true"
:hover-state-enabled="true"
@selection-changed="onDataSelectionChanged"
@exporting="onExporting"
:allow-column-resizing="true"
column-resizing-mode="widget"
:word-wrap-enabled="true"
>
<DxSelection mode="single" />
<DxPaging :enabled="false" />
<DxScrolling column-rendering-mode="virtual" mode="virtual" />
<DxSearchPanel :visible="true" :highlight-case-sensitive="true" />
<DxExport
:enabled="true"
:formats="['pdf', 'xlsx', 'document']"
:allow-export-selected-data="false"
/>
<DxColumnFixing :enabled="true" />
<DxColumn
alignment="center"
data-field="nama_ulp"
caption="Nama Unit"
css-class="custom-table-column"
cell-template="formatText"
/>
<DxColumn alignment="center" caption="Total WO PLN Mobile" css-class="custom-table-column">
<DxColumn
:width="170"
alignment="center"
data-field="wo_total"
data-type="number"
caption="a"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
<DxColumn
alignment="center"
caption="Total Pengaduan Yang Diselesaikan Secara Anomali"
css-class="custom-table-column"
>
<DxColumn
:width="170"
alignment="center"
data-field="total_anomali_marking"
data-type="number"
caption="b"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
<DxColumn
alignment="center"
caption="% Pengaduan Yang Diselesaikan Secara Anomali"
css-class="custom-table-column"
>
<DxColumn
:width="170"
alignment="center"
data-field="persen_anomali_marking"
data-type="number"
caption="c=b/a"
css-class="custom-table-column"
cell-template="formatPercentage"
/>
</DxColumn>
<template #formatNumber="{ data }">
<p class="text-right cursor-pointer" @click="showData()">
{{
isNumber(data.text)
? data.column.caption == '%'
? formatPercentage(data.text)
: formatNumber(data.text)
: data.text
}}
</p>
</template>
<template #formatPercentage="{ data }">
<p class="text-right cursor-pointer" @click="showData()">
{{ isNumber(data.text) ? formatPercentage(data.text) : data.text }}
</p>
</template>
<template #formatText="{ data }">
<p class="text-left cursor-pointer" @click="showData()">
{{ data.text }}
</p>
</template>
<template #formatTime="{ data }" @click="showData()">
<p class="!text-right">
{{ parseInt(data.text) ? formatWaktu(data.text) : '-' }}
</p>
</template>
</DxDataGrid>
</template>
<script setup lang="ts">
import { DxDataGrid } from 'devextreme-vue'
import {
DxColumn,
DxColumnFixing,
DxExport,
DxPaging,
DxScrolling,
DxSearchPanel,
DxSelection
} from 'devextreme-vue/data-grid'
import { jsPDF } from 'jspdf'
import { exportDataGrid as exportToPdf } from 'devextreme/pdf_exporter'
import { exportDataGrid as exportToExcel } from 'devextreme/excel_exporter'
import { saveAs } from 'file-saver'
import { Workbook } from 'exceljs'
import { computed, ref } from 'vue'
import { formatNumber, formatPercentage, isNumber } from '@/utils/numbers'
import { formatWaktu } from '@/components/Form/FiltersType/reference'
const props = defineProps({
data: Array as () => any[]
})
const data = computed(() => props.data)
const dataSub = ref<any[]>([])
const dataSelected = ref<any>({})
const dataSubSelected = ref<any>({})
const showDetail = ref(false)
const showData = () => {
showDetail.value = true
}
const closeDetail = () => {
showDetail.value = false
}
const onExporting = (e: any) => {
if (e.format === 'pdf') {
const doc = new jsPDF()
exportToPdf({
jsPDFDocument: doc,
component: e.component,
indent: 5
}).then(() => {
doc.save(`.pdf`)
})
} else {
const workbook = new Workbook()
const worksheet = workbook.addWorksheet('Employees')
exportToExcel({
component: e.component,
worksheet,
autoFilterEnabled: true
}).then(() => {
workbook.xlsx.writeBuffer().then((buffer: any) => {
saveAs(new Blob([buffer], { type: 'application/octet-stream' }), 'DataGrid.xlsx')
})
})
e.cancel = true
}
}
const onDataSelectionChanged = ({ selectedRowsData }: any) => {
const dataSelected = selectedRowsData[0]
console.log(data)
}
</script>

View File

@ -0,0 +1,507 @@
<template>
<div class="mt-4 lg:mt-6 max-w-7xl">
<h1 class="text-xl font-medium md:text-2xl text-dark">Laporan Pengaduan Total</h1>
</div>
<DxDataGrid
class="max-h-[calc(100vh-140px)] mb-10"
:data-source="data"
:show-column-lines="true"
:show-row-lines="false"
:show-borders="true"
:row-alternation-enabled="true"
:hover-state-enabled="true"
@selection-changed="onDataSelectionChanged"
:column-width="100"
@exporting="onExporting"
:allow-column-resizing="true"
column-resizing-mode="widget"
:word-wrap-enabled="true"
>
<DxSelection mode="single" />
<DxPaging :enabled="false" />
<DxScrolling column-rendering-mode="virtual" mode="virtual" />
<DxLoadPanel
:position="position"
:show-indicator="showIndicator"
:show-pane="showPane"
:shading="shading"
v-if="loading"
v-model:visible="loading"
:enabled="true"
/>
<DxSearchPanel :visible="true" :highlight-case-sensitive="true" />
<DxExport
:enabled="true"
:formats="['pdf', 'xlsx', 'document']"
:allow-export-selected-data="false"
/>
<DxColumnFixing :enabled="true" />
<DxColumn
:width="170"
alignment="center"
data-field="nama_ulp"
caption="Nama Unit"
css-class="custom-table-column"
cell-template="formatText"
/>
<DxColumn
:width="170"
alignment="center"
data-field="nama_ulp"
caption="Nama Unit"
name="namaUnit"
css-class="custom-table-column"
cell-template="formatText"
:group-index="0"
/>
<DxColumn alignment="center" caption="Total WO" css-class="custom-table-column">
<DxColumn alignment="center" caption="CC 123" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="wo_cc123"
data-type="number"
caption="a"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
<DxColumn alignment="center" caption="PLN Mobile" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="wo_pln_mobile"
data-type="number"
caption="b"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
<DxColumn alignment="center" caption="Loket" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="wo_loket"
data-type="number"
caption="c"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
<DxColumn alignment="center" caption="Lainnya" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="wo_lainnya"
data-type="number"
caption="d"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
<DxColumn alignment="center" caption="Total" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="wo_total"
data-type="number"
caption="e=a+b+c+d"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
</DxColumn>
<DxColumn
alignment="center"
caption="Total Pengaduan Yang Diselesaikan Secara Anomali"
css-class="custom-table-column"
>
<DxColumn alignment="center" caption="PLN Mobile" css-class="custom-table-column">
<DxColumn alignment="center" caption="f" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="anomali_pln_mobile_marking"
data-type="number"
caption="Marking"
css-class="custom-table-column"
cell-template="formatNumber"
/>
<DxColumn
:width="150"
alignment="center"
data-field="anomali_pln_mobile_non_marking"
data-type="number"
caption="Non Marking"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
</DxColumn>
<DxColumn alignment="center" caption="CC 123" css-class="custom-table-column">
<DxColumn alignment="center" caption="g" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="anomali_cc123_marking"
data-type="number"
caption="Marking"
css-class="custom-table-column"
cell-template="formatNumber"
/>
<DxColumn
:width="150"
alignment="center"
data-field="anomali_cc123_non_marking"
data-type="number"
caption="Non Marking"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
</DxColumn>
<DxColumn alignment="center" caption="Total" css-class="custom-table-column">
<DxColumn alignment="center" caption="h=f+g" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="total_anomali_marking"
data-type="number"
caption="Marking"
css-class="custom-table-column"
cell-template="formatNumber"
/>
<DxColumn
:width="150"
alignment="center"
data-field="total_anomali_non_marking"
data-type="number"
caption="Non Marking"
css-class="custom-table-column"
cell-template="formatNumber"
/>
</DxColumn>
</DxColumn>
</DxColumn>
<DxColumn
alignment="center"
caption="% Pengaduan Yang Diselesaikan Secara Anomali"
css-class="custom-table-column"
>
<DxColumn alignment="center" caption="PLN Mobile" css-class="custom-table-column">
<DxColumn alignment="center" caption="i=f/e" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="persen_anomali_pln_mobile_marking"
data-type="number"
caption="Marking"
css-class="custom-table-column"
cell-template="formatPercentage"
/>
<DxColumn
:width="150"
alignment="center"
data-field="persen_anomali_pln_mobile_non_marking"
data-type="number"
caption="Non Marking"
css-class="custom-table-column"
cell-template="formatPercentage"
/>
</DxColumn>
</DxColumn>
<DxColumn alignment="center" caption="CC 123" css-class="custom-table-column">
<DxColumn alignment="center" caption="j=g/e" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="persen_anomali_cc123_marking"
data-type="number"
caption="Marking"
css-class="custom-table-column"
cell-template="formatPercentage"
/>
<DxColumn
:width="150"
alignment="center"
data-field="persen_anomali_cc123_non_marking"
data-type="number"
caption="Non Marking"
css-class="custom-table-column"
cell-template="formatPercentage"
/>
</DxColumn>
</DxColumn>
<DxColumn alignment="center" caption="Total" css-class="custom-table-column">
<DxColumn alignment="center" caption="k=i+j" css-class="custom-table-column">
<DxColumn
:width="150"
alignment="center"
data-field="persen_anomali_marking"
data-type="number"
caption="Marking"
css-class="custom-table-column"
cell-template="formatPercentage"
/>
<DxColumn
:width="150"
alignment="center"
data-field="persen_anomali_non_marking"
data-type="number"
caption="Non Marking"
css-class="custom-table-column"
cell-template="formatPercentage"
/>
</DxColumn>
</DxColumn>
</DxColumn>
<template #formatNumber="{ data }">
<p class="text-right cursor-pointer" @click="showData()">
{{
isNumber(data.text)
? data.column.caption == '%'
? formatPercentage(data.text)
: formatNumber(data.text)
: data.text
}}
</p>
</template>
<template #formatPercentage="{ data }">
<p class="text-right cursor-pointer" @click="showData()">
{{ isNumber(data.text) ? formatPercentage(data.text) : data.text }}
</p>
</template>
<template #formatText="{ data }">
<p class="text-left cursor-pointer" @click="showData()">
{{ data.text }}
</p>
</template>
<template #formatTime="{ data }" @click="showData()">
<p class="!text-right">
{{ parseInt(data.text) ? formatWaktu(data.text) : '-' }}
</p>
</template>
<DxSummary>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="wo_cc123"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="wo_pln_mobile"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="wo_loket"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="wo_lainnya"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="wo_total"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="anomali_pln_mobile_marking"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="anomali_pln_mobile_non_marking"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="anomali_cc123_marking"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="anomali_cc123_non_marking"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="total_anomali_marking"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="total_anomali_non_marking"
summary-type="sum"
css-class="!text-right"
:customize-text="(e: any) => formatNumber(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="persen_anomali_pln_mobile_marking"
summary-type="avg"
css-class="!text-right"
:customize-text="(e: any) => formatPercentage(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="persen_anomali_pln_mobile_non_marking"
summary-type="avg"
css-class="!text-right"
:customize-text="(e: any) => formatPercentage(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="persen_anomali_cc123_marking"
summary-type="avg"
css-class="!text-right"
:customize-text="(e: any) => formatPercentage(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="persen_anomali_cc123_non_marking"
summary-type="avg"
css-class="!text-right"
:customize-text="(e: any) => formatPercentage(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="persen_anomali_marking"
summary-type="avg"
css-class="!text-right"
:customize-text="(e: any) => formatPercentage(parseFloat(e.value.toString()))"
/>
<DxGroupItem
:show-in-group-footer="false"
:align-by-column="true"
column="persen_anomali_non_marking"
summary-type="avg"
css-class="!text-right"
:customize-text="(e: any) => formatPercentage(parseFloat(e.value.toString()))"
/>
</DxSummary>
</DxDataGrid>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { DxDataGrid } from 'devextreme-vue'
import {
DxColumn,
DxColumnFixing,
DxExport,
DxGroupItem,
DxLoadPanel,
DxPaging,
DxScrolling,
DxSearchPanel,
DxSelection,
DxSummary
} from 'devextreme-vue/data-grid'
import { jsPDF } from 'jspdf'
import { exportDataGrid as exportToPdf } from 'devextreme/pdf_exporter'
import { exportDataGrid as exportToExcel } from 'devextreme/excel_exporter'
import { saveAs } from 'file-saver'
import { Workbook } from 'exceljs'
import { formatWaktu } from '@/components/Form/FiltersType/reference'
import { formatNumber, formatPercentage, isNumber } from '@/utils/numbers'
const position = { of: '#data' }
const showIndicator = ref(true)
const loading = ref(computed(() => props.loading))
const shading = ref(true)
const showPane = ref(true)
const props = defineProps({
data: Array as () => any[],
loading: {
type: Boolean,
default: false
}
})
const showDialog = ref(false)
const data = computed(() => props.data)
const dataSelected = ref()
const dataSub = ref([])
const dataSubSelected = ref()
const showDetail = ref(false)
const showData = () => (showDetail.value = true)
const closeDetail = () => (showDetail.value = false)
const onExporting = (e: any) => {
if (e.format === 'pdf') {
const doc = new jsPDF()
exportToPdf({
jsPDFDocument: doc,
component: e.component,
indent: 5
}).then(() => {
doc.save(`.pdf`)
})
} else {
const workbook = new Workbook()
const worksheet = workbook.addWorksheet('Employees')
exportToExcel({
component: e.component,
worksheet,
autoFilterEnabled: true
}).then(() => {
workbook.xlsx.writeBuffer().then((buffer: any) => {
saveAs(new Blob([buffer], { type: 'application/octet-stream' }), 'DataGrid.xlsx')
})
})
e.cancel = true
}
}
const onDataSelectionChanged = ({ selectedRowsData }: any) => {
const dataSelected = selectedRowsData[0]
console.log(data)
}
</script>

View File

@ -0,0 +1,79 @@
<template>
<Filters @run-search="() => filterData(filters)" class="mb-4">
<Type4 @update:filters="(value) => filters = value" />
</Filters>
<Anomali_LAPPKU_LPT :data="data" />
<Anomali_LAPPKU_LPP :data="data" />
</template>
<script setup lang="ts">
import Filters from '@/components/Form/Filters.vue'
import { ref } from 'vue'
import { Anomali_LAPPKU_LPT, Anomali_LAPPKU_LPP } from '../.'
import { Type4 } from '@/components/Form/FiltersType'
import { useQuery } from '@vue/apollo-composable'
import gql from 'graphql-tag'
const data = ref<any[]>([])
const GET_laporanCheckInCheckOut = gql`
query laporanCheckInCheckOut($dateFrom: Date!, $dateTo: Date!, $posko: String, $idUid: Int, $idUp3: Int) {
laporanCheckInCheckOut(
dateFrom: $dateFrom
dateTo: $dateTo
posko: $posko
idUid: $idUid
idUp3: $idUp3
) {
avg_durasi_wo_gangguan_individual
avg_durasi_wo_penugasan_khusus
avg_rct_wo_gangguan_individual
avg_rpt_wo_gangguan_individual
jumlah_wo_gangguan_individual
jumlah_wo_penugasan_khusus
personil_yantek
user_regu
}
}
`
const filterData = (params: any) => {
const { posko, uid, up3 } = params
const dateValue = params.periode.split(' s/d ')
refetch({
dateFrom: dateValue[0] ? dateValue[0].split('-').reverse().join('-') : new Date().toISOString().slice(0, 10),
dateTo: dateValue[1] ? dateValue[1].split('-').reverse().join('-') : new Date().toISOString().slice(0, 10),
posko: posko ? posko.id : "",
idUid: uid ? uid.id : 0,
idUp3: up3 ? up3.id : 0
})
onResult((queryResult) => {
if (queryResult.data != undefined) {
queryResult.data.daftarGangguanDialihkanKePoskoLain.forEach((item: any) => {
data.value = [
...data.value,
{
...item,
}
]
})
}
console.log(queryResult.data)
console.log(queryResult.loading)
console.log(queryResult.networkStatus)
})
onError((error) => {
console.log(error)
})
}
const { onResult, onError, loading, refetch } = useQuery(
GET_laporanCheckInCheckOut,
{
dateFrom: new Date().toISOString().slice(0, 10),
dateTo: new Date().toISOString().slice(0, 10),
posko: '',
idUid: 0,
idUp3: 0
}
)
const filters = ref()
</script>

View File

@ -0,0 +1,91 @@
<template>
<div class="mt-4 lg:mt-6 max-w-7xl">
<h1 class="text-xl font-medium md:text-2xl text-dark">
Laporan Pengaduan PLN Mobile
</h1>
</div>
<DxDataGrid class="max-h-[calc(100vh-140px)] mb-10" :show-column-lines="true" :show-row-lines="false"
:show-borders="true" :row-alternation-enabled="true" :hover-state-enabled="true"
@selection-changed="onSelectionChanged" @exporting="onExporting" :allow-column-resizing="true"
column-resizing-mode="widget" :word-wrap-enabled="true">
<DxSelection mode="single" />
<DxPaging :enabled="false" />
<DxScrolling column-rendering-mode="virtual" mode="virtual" />
<DxLoadPanel :position="position" :show-indicator="showIndicator" :show-pane="showPane" :shading="shading"
v-if="loading" v-model:visible="loading" :enabled="true" />
<DxSearchPanel :visible="true" :highlight-case-sensitive="true" />
<DxExport :enabled="true" :formats="['pdf', 'xlsx', 'document']" :allow-export-selected-data="false" />
<DxColumnFixing :enabled="true" />
<DxColumn alignment="center" data-field="" caption="Nama Unit" css-class="custom-table-column" />
<DxColumn alignment="center" caption="Total WO PLN Mobile" css-class="custom-table-column">
<DxColumn :width="170" alignment="center" data-field="" data-type="number" caption="a"
css-class="custom-table-column" />
</DxColumn>
<DxColumn alignment="center" caption="Total Pengaduan Yang Diselesaikan Secara Anomali"
css-class="custom-table-column">
<DxColumn :width="170" alignment="center" data-field="" data-type="number" caption="b"
css-class="custom-table-column" />
</DxColumn>
<DxColumn alignment="center" caption="% Pengaduan Yang Diselesaikan Secara Anomali" css-class="custom-table-column">
<DxColumn :width="170" alignment="center" data-field="" data-type="number" caption="c=b/a"
css-class="custom-table-column" />
</DxColumn>
</DxDataGrid>
</template>
<script setup lang="ts">
import { DxDataGrid } from 'devextreme-vue'
import { DxColumn, DxColumnFixing, DxExport, DxLoadPanel, DxPaging, DxScrolling, DxSearchPanel, DxSelection } from 'devextreme-vue/data-grid'
import { jsPDF } from 'jspdf'
import { exportDataGrid as exportToPdf } from 'devextreme/pdf_exporter'
import { exportDataGrid as exportToExcel } from 'devextreme/excel_exporter'
import { saveAs } from 'file-saver'
import { Workbook } from 'exceljs'
import { computed, ref } from 'vue'
const position = { of: '#data' };
const showIndicator = ref(true);
const shading = ref(true);
const showPane = ref(true);
const props = defineProps({
data: Array as () => any[],
})
const data = computed(() => props.data)
const loading = ref(false)
const onExporting = (e: any) => {
if (e.format === 'pdf') {
const doc = new jsPDF()
exportToPdf({
jsPDFDocument: doc,
component: e.component,
indent: 5,
}).then(() => {
doc.save(`.pdf`)
})
} else {
const workbook = new Workbook()
const worksheet = workbook.addWorksheet('Employees')
exportToExcel({
component: e.component,
worksheet,
autoFilterEnabled: true,
}).then(() => {
workbook.xlsx.writeBuffer().then((buffer: any) => {
saveAs(new Blob([buffer], { type: 'application/octet-stream' }), 'DataGrid.xlsx')
})
})
e.cancel = true
}
}
const onSelectionChanged = ({ selectedRowsData }: any) => {
const data = selectedRowsData[0]
console.log(data)
}
</script>

View File

@ -0,0 +1,129 @@
<template>
<div class="mt-4 lg:mt-6 max-w-7xl">
<h1 class="text-xl font-medium md:text-2xl text-dark">
Laporan Pengaduan Total
</h1>
</div>
<DxDataGrid class="max-h-[calc(100vh-140px)] mb-10" :show-column-lines="true" :show-row-lines="false"
:show-borders="true" :row-alternation-enabled="true" :hover-state-enabled="true"
@selection-changed="onSelectionChanged" :column-width="100" @exporting="onExporting" :allow-column-resizing="true"
column-resizing-mode="widget" :word-wrap-enabled="true">
<DxSelection mode="single" />
<DxPaging :enabled="false" />
<DxScrolling column-rendering-mode="virtual" mode="virtual" />
<DxLoadPanel :position="position" :show-indicator="showIndicator" :show-pane="showPane" :shading="shading"
v-if="loading" v-model:visible="loading" :enabled="true" />
<DxSearchPanel :visible="true" :highlight-case-sensitive="true" />
<DxExport :enabled="true" :formats="['pdf', 'xlsx', 'document']" :allow-export-selected-data="false" />
<DxColumnFixing :enabled="true" />
<DxColumn :width="170" alignment="center" data-field="" caption="Nama Unit" css-class="custom-table-column" />
<DxColumn alignment="center" caption="Total WO" css-class="custom-table-column">
<DxColumn alignment="center" caption="CC 123" css-class="custom-table-column">
<DxColumn :width="150" alignment="center" data-field="" data-type="number" caption="a"
css-class="custom-table-column" />
</DxColumn>
<DxColumn alignment="center" caption="PLN Mobile" css-class="custom-table-column">
<DxColumn :width="150" alignment="center" data-field="" data-type="number" caption="b"
css-class="custom-table-column" />
</DxColumn>
<DxColumn alignment="center" caption="Loket" css-class="custom-table-column">
<DxColumn :width="150" alignment="center" data-field="" data-type="number" caption="c"
css-class="custom-table-column" />
</DxColumn>
<DxColumn alignment="center" caption="Lainnya" css-class="custom-table-column">
<DxColumn :width="150" alignment="center" data-field="" data-type="number" caption="d"
css-class="custom-table-column" />
</DxColumn>
<DxColumn alignment="center" caption="Total" css-class="custom-table-column">
<DxColumn :width="150" alignment="center" data-field="" data-type="number" caption="e=a+b+c+d"
css-class="custom-table-column" />
</DxColumn>
</DxColumn>
<DxColumn alignment="center" caption="Total Pengaduan Yang Diselesaikan Secara Anomali"
css-class="custom-table-column">
<DxColumn alignment="center" caption="PLN Mobile" css-class="custom-table-column">
<DxColumn :width="150" alignment="center" data-field="" data-type="number" caption="f"
css-class="custom-table-column" />
</DxColumn>
<DxColumn alignment="center" caption="CC 123" css-class="custom-table-column">
<DxColumn :width="150" alignment="center" data-field="" data-type="number" caption="g"
css-class="custom-table-column" />
</DxColumn>
<DxColumn alignment="center" caption="Total" css-class="custom-table-column">
<DxColumn :width="150" alignment="center" data-field="" data-type="number" caption="h=f+g"
css-class="custom-table-column" />
</DxColumn>
</DxColumn>
<DxColumn alignment="center" caption="% Pengaduan Yang Diselesaikan Secara Anomali" css-class="custom-table-column">
<DxColumn alignment="center" caption="PLN Mobile" css-class="custom-table-column">
<DxColumn :width="150" alignment="center" data-field="" data-type="number" caption="i=f/e"
css-class="custom-table-column" />
</DxColumn>
<DxColumn alignment="center" caption="CC 123" css-class="custom-table-column">
<DxColumn :width="150" alignment="center" data-field="" data-type="number" caption="j=g/e"
css-class="custom-table-column" />
</DxColumn>
<DxColumn alignment="center" caption="Total" css-class="custom-table-column">
<DxColumn :width="150" alignment="center" data-field="" data-type="number" caption="k=i+j"
css-class="custom-table-column" />
</DxColumn>
</DxColumn>
</DxDataGrid>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { DxDataGrid } from 'devextreme-vue'
import { DxColumn, DxColumnFixing, DxExport, DxLoadPanel, DxPaging, DxScrolling, DxSearchPanel, DxSelection } from 'devextreme-vue/data-grid'
import { jsPDF } from 'jspdf'
import { exportDataGrid as exportToPdf } from 'devextreme/pdf_exporter'
import { exportDataGrid as exportToExcel } from 'devextreme/excel_exporter'
import { saveAs } from 'file-saver'
import { Workbook } from 'exceljs'
const position = { of: '#data' }
const showIndicator = ref(true)
const shading = ref(true)
const showPane = ref(true)
const loading = ref(false)
const props = defineProps({
data: Array as () => any[],
})
const data = computed(() => props.data)
const onExporting = (e: any) => {
if (e.format === 'pdf') {
const doc = new jsPDF()
exportToPdf({
jsPDFDocument: doc,
component: e.component,
indent: 5,
}).then(() => {
doc.save(`.pdf`)
})
} else {
const workbook = new Workbook()
const worksheet = workbook.addWorksheet('Employees')
exportToExcel({
component: e.component,
worksheet,
autoFilterEnabled: true,
}).then(() => {
workbook.xlsx.writeBuffer().then((buffer: any) => {
saveAs(new Blob([buffer], { type: 'application/octet-stream' }), 'DataGrid.xlsx')
})
})
e.cancel = true
}
}
const onSelectionChanged = ({ selectedRowsData }: any) => {
const data = selectedRowsData[0]
console.log(data)
}
</script>

Some files were not shown because too many files have changed in this diff Show More