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

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

@ -2,3 +2,5 @@ VITE_BASE_URL=http://localhost:5173
VITE_BASE_DIRECTORY=/ VITE_BASE_DIRECTORY=/
VITE_APP_VERSION=0.0.1 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

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

@ -2,3 +2,5 @@ VITE_BASE_URL=https://api.domain.com/v1/
VITE_BASE_DIRECTORY=/ VITE_BASE_DIRECTORY=/
VITE_APP_VERSION=0.0.1 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

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

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

View File

@ -23,8 +23,7 @@ jobs:
- name: Build the Docker image - name: Build the Docker image
run: | run: |
docker build . -t defuj/apkt-eis docker build . --file Dockerfile --tag defuj/apkt-eis:v1.0.1-release
docker image tag defuj/apkt-eis defuj/apkt-eis:v1.0.1-release
docker push 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 node_modules
.DS_Store .DS_Store
dist dist
build
dist-ssr dist-ssr
coverage coverage
*.local *.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

27
Dockerfile Normal file → Executable file
View File

@ -1,13 +1,20 @@
FROM node:lts-alpine as build-stage # syntax=docker/dockerfile:1
WORKDIR /app # build stage
COPY package*.json ./ # FROM node:lts-alpine as builder
RUN npm install # WORKDIR /apkt
COPY . . # COPY package*.json ./
RUN npm run build # 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
FROM nginx:stable-alpine as production-stage COPY /dist /usr/share/nginx/html
COPY --from=build-stage /app/dist /usr/share/nginx/html COPY /nginx.conf /etc/nginx/nginx.conf
COPY --from=build-stage /app/nginx.conf /etc/nginx/nginx.conf
EXPOSE 32166 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. ### Keluhan > Rekapitulasi
| CODE | MENU | FILE |
## Recommended IDE Setup | ------- | ------------------- | ------------ |
| MON0010 | Jumlah Kali Keluhan | Table_45.vue |
[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
```

View File

@ -14,7 +14,7 @@ spec:
spec: spec:
containers: containers:
- name: apkt-eis - name: apkt-eis
image: defuj/apkt-eis:v1.0.1-dev image: defuj/apkt-eis:v0.0.10-vm
ports: ports:
- containerPort: 80 - containerPort: 80
--- ---

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

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

File diff suppressed because it is too large Load Diff

39
package.json Normal file → Executable file
View File

@ -11,31 +11,37 @@
"build-only": "vite build", "build-only": "vite build",
"type-check": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false", "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", "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/", "format": "prettier --write src/"
"prepare": "tw-patch install"
}, },
"dependencies": { "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/tailwindcss": "^0.2.0",
"@headlessui/vue": "^1.7.16", "@headlessui/vue": "^1.7.19",
"@heroicons/vue": "^2.0.18", "@heroicons/vue": "^2.0.18",
"@lottiefiles/lottie-player": "^2.0.2", "@lottiefiles/lottie-player": "^2.0.4",
"@phosphor-icons/vue": "^2.1.6", "@phosphor-icons/vue": "^2.1.6",
"@types/qs": "^6.9.9", "@types/qs": "^6.9.12",
"@types/uuid": "^9.0.2", "@types/uuid": "^9.0.8",
"@vue/apollo-option": "^4.0.0-beta.12", "@types/vue-select": "^3.16.8",
"devextreme": "23.1.5", "@vue/apollo-components": "^4.0.0",
"devextreme-vue": "23.1.5", "@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", "dotenv": "^16.3.1",
"encrypt-storage": "^2.12.16", "encrypt-storage": "^2.12.22",
"exceljs": "^4.4.0", "exceljs": "^4.4.0",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"graphql": "^16.8.1", "graphql": "^16.8.1",
"graphql-tag": "^2.12.6", "graphql-tag": "^2.12.6",
"jspdf": "^2.5.1", "jspdf": "^2.5.1",
"jspdf-autotable": "^3.8.2",
"pinia": "^2.1.3", "pinia": "^2.1.3",
"qs": "^6.11.2", "qs": "^6.11.2",
"uuid": "^9.0.0", "uuid": "^9.0.1",
"vue": "^3.3.4", "vue": "^3.3.4",
"vue-router": "^4.2.2", "vue-router": "^4.2.2",
"vue-tailwind-datepicker": "^1.6.1" "vue-tailwind-datepicker": "^1.6.1"
@ -44,7 +50,7 @@
"@rushstack/eslint-patch": "^1.5.1", "@rushstack/eslint-patch": "^1.5.1",
"@tailwindcss/aspect-ratio": "^0.4.2", "@tailwindcss/aspect-ratio": "^0.4.2",
"@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/container-queries": "^0.1.1",
"@tailwindcss/forms": "^0.5.6", "@tailwindcss/forms": "^0.5.7",
"@tailwindcss/typography": "^0.5.10", "@tailwindcss/typography": "^0.5.10",
"@tsconfig/node18": "^2.0.1", "@tsconfig/node18": "^2.0.1",
"@types/file-saver": "^2.0.6", "@types/file-saver": "^2.0.6",
@ -60,15 +66,12 @@
"eslint": "^8.39.0", "eslint": "^8.39.0",
"eslint-plugin-vue": "^9.11.0", "eslint-plugin-vue": "^9.11.0",
"jsdom": "^22.1.0", "jsdom": "^22.1.0",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.24", "postcss": "^8.4.24",
"prettier": "^3.0.3", "prettier": "^3.0.3",
"tailwindcss": "^3.3.2", "tailwindcss": "^3.3.2",
"tailwindcss-patch": "^2.2.2",
"typescript": "~5.2.2", "typescript": "~5.2.2",
"unplugin-tailwindcss-mangle": "^2.2.2",
"vite": "^4.3.9", "vite": "^4.3.9",
"vitest": "^0.34.6", "vitest": "^1.3.1",
"vue-tsc": "^1.6.5" "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 '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 url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;700&display=swap');
@import './style.css'; @import './style.css';
@import './devextreme.custom.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;
}

3021
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; @apply flex-shrink-0 block px-4 py-2 border-b bg-primary-500 border-gray-50;
} }
/* Aside */ /* Aside */
.aside-text{
@apply text-xs;
}
.aside-single-item { .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 { .aside-single-item-active {
@apply aside-single-item bg-primary-500 text-white font-bold; @apply aside-single-item bg-primary-500 text-white font-bold;
@ -47,4 +50,17 @@
.custom-table-column { .custom-table-column {
@apply !align-middle text-sm font-medium text-primary-800; @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', type: String as () => 'button' | 'submit' | 'reset',
default: 'button' default: 'button'
}, },
onClick: {
type: Function as unknown as () => (payload: MouseEvent) => void,
default: () => {}
},
label: { label: {
type: String, type: String,
default: '' 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' 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> </script>
<template> <template>
<button <button
:type="type" :type="type"
@click="onClick" @click="emit('on:click')"
:disabled="isLoading ? true : disabled" :disabled="isLoading ? true : disabled"
:class="['px-3 py-2 text-sm font-semibold', buttonStyle, className]" :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"> <script setup lang="ts">
import * as LottiePlayer from "@lottiefiles/lottie-player";
defineProps({ defineProps({
type: { type: {
type: String as () => "button" | "submit" | "reset", type: String as () => "button" | "submit" | "reset",

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

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

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

@ -1,38 +1,51 @@
<script setup lang="ts"> <script setup lang="ts">
import { PhCalendarBlank } from '@phosphor-icons/vue'; import { PhCalendarBlank } from '@phosphor-icons/vue'
import { ref } from 'vue' import { ref, watch } from 'vue'
import VueTailwindDatepicker from 'vue-tailwind-datepicker' import VueTailwindDatepicker from 'vue-tailwind-datepicker'
const dateValue = ref('') const dateValue = ref('')
const formatter = ref({ const formatter = ref({
date: 'DD MMM YYYY', date: 'DD-MM-YYYY',
month: 'MMM' 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> </script>
<template> <template>
<div class="flex"> <div class="flex">
<vue-tailwind-datepicker <vue-tailwind-datepicker v-model="dateValue" :formatter="formatter" separator=" s/d " :shortcuts="customShortcuts"
v-model="dateValue" :auto-apply="true" as-single use-range v-slot="{ value, placeholder }">
:formatter="formatter"
separator=" s/d "
:shortcuts="false"
:auto-apply="false"
as-single
use-range
v-slot="{ value, placeholder }"
>
<div class="flex"> <div class="flex">
<div class="flex-1"> <div class="flex-1">
<button <button type="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">
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"
>
<span class="text-gray-900"> <span class="text-gray-900">
{{ value || placeholder }} {{ value || placeholder }}
</span> </span>
<PhCalendarBlank size="18" weight="regular"/> <PhCalendarBlank size="18" weight="regular" />
</button> </button>
</div> </div>
</div> </div>

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, DialogTitle,
TransitionChild, TransitionChild,
TransitionRoot TransitionRoot
} from '@headlessui/vue' } from '@headlessui/vue';
defineProps({ defineProps({
open: { open: {
type: Boolean, type: Boolean,
@ -15,6 +15,10 @@ defineProps({
type: String, type: String,
required: true, required: true,
}, },
fullWidth: {
type: Boolean,
default: false,
},
}) })
const emit = defineEmits(['onClose']) const emit = defineEmits(['onClose'])
const handleOnClose = () => { const handleOnClose = () => {
@ -38,12 +42,13 @@ const handleOnClose = () => {
leave-from="opacity-100 translate-y-0 sm:scale-100" leave-from="opacity-100 translate-y-0 sm:scale-100"
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"> leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95">
<DialogPanel <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 --> <!-- Body Section -->
<div class="px-4 py-4 bg-gray-50"> <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"> <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 }} {{ title }}
</DialogTitle> </DialogTitle>
<div class="flex items-center ml-3 h-7"> <div class="flex items-center ml-3 h-7">

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

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

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

@ -1,32 +1,87 @@
<script setup lang="ts"> <script setup lang="ts">
import Select from '@/components/Select.vue' import Select from '@/components/Select.vue';
import DatePicker from '@/components/DatePicker.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> </script>
<template> <template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<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"/> <Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" /> <Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="up3" :placeholder="up3placeholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Posko:</label> <label class="filter-input-label">Posko:</label>
<Select placeholder="Semua Posko" /> <Select @update:selected="setPosko($event)" :data="itemsPosko" :selected="posko"
:placeholder="poskoPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label> <label class="filter-input-label">Periode Tanggal:</label>
<DatePicker @update:date-value="(value) => (data.periode = value)" />
<DatePicker />
</div> </div>
</div>
</template> </template>

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

@ -1,44 +1,94 @@
<script setup lang="ts"> <script setup lang="ts">
import Select from '@/components/Select.vue' import { onMounted, ref } from 'vue'
import DatePicker from '@/components/DatePicker.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> </script>
<template> <template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<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"/> <Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" /> <Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="up3" :placeholder="up3Placeholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Layanan Pelanggan:</label>
>Unit Layanan Pelanggan:</label
>
<Select placeholder="Semua Unit Layanan Pelanggan" /> <Select @update:selected="setUlp($event)" :data="itemsUlp" :selected="ulp" :placeholder="ulpPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label> <label class="filter-input-label">Periode Tanggal:</label>
<DatePicker /> <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"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Lapor Ulang:</label> <label class="filter-input-label">Lapor Ulang:</label>
<div class="grid grid-flow-col auto-cols-auto gap-x-1.5"> <div class="flex flex-1 justify-between gap-x-1.5">
<Select placeholder="1" /> <InputNumber @update:time-value="(value) => (data.minJmlLapor = value)" class="flex flex-1" />
<small class="flex items-center">s/d</small> <small class="flex items-center">s/d</small>
<Select placeholder="2" /> <InputNumber @update:time-value="(value) => (data.maxJmlLapor = value)" class="flex flex-1" />
</div> </div>
</div> </div>
</div>
</template> </template>

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

@ -1,47 +1,191 @@
<script setup lang="ts"> <script setup lang="ts">
import Select from '@/components/Select.vue' interface SlaOption {
import DatePicker from '@/components/DatePicker.vue' 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> </script>
<template> <template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<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"/> <Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" /> <Select
@update:selected="setUp3($event)"
:data="itemsUp3"
:selected="up3"
:placeholder="up3Placeholder"
/>
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Layanan Pelanggan:</label>
>Unit Layanan Pelanggan:</label
>
<Select placeholder="Semua Unit Layanan Pelanggan" /> <Select
@update:selected="setUlp($event)"
:data="itemsUlp"
:placeholder="ulpPlaceholder"
:selected="ulp"
/>
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label> <label class="filter-input-label">Periode Tanggal:</label>
<DatePicker /> <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"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Durasi:</label> <label class="filter-input-label">Durasi:</label>
<div class="flex flex-col gap-y-1"> <div class="flex flex-col gap-y-2">
<Select placeholder="Durasi Menit" /> <Select @update:selected="changeDuration($event)" :data="sla" placeholder="Durasi Menit" />
<div class="grid grid-flow-col auto-cols-auto gap-x-1.5"> <div class="flex flex-1 justify-between gap-x-1.5" :class="[isHidden ? 'hidden' : '']">
<Select placeholder="1" /> <InputWithSuffix
:value="`${data.minTime} Menit`"
@update:text="setMin($event)"
class="flex flex-1"
/>
<small class="flex items-center">s/d</small> <small class="flex items-center">s/d</small>
<Select placeholder="2" /> <InputWithSuffix
:value="`${data.maxTime} Menit`"
@update:text="setMax($event)"
class="flex flex-1"
/>
</div>
</div> </div>
</div> </div>
</div> </div>

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

@ -1,49 +1,124 @@
<script setup lang="ts"> <script setup lang="ts">
import Select from '@/components/Select.vue' import Select from '@/components/Select.vue';
import DatePicker from '@/components/DatePicker.vue' import DatePicker from '@/components/DatePicker.vue';
import InputWithSuffix from '../InputWithSuffix.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> </script>
<template> <template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<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"/> <Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" /> <Select @update:selected="setUp3($event)" :data="itemsUp3" :placeholder="up3Placeholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Layanan Pelanggan:</label>
>Unit Layanan Pelanggan:</label
>
<Select placeholder="Semua Unit Layanan Pelanggan" /> <Select @update:selected="setUlp($event)" :data="itemsUlp" :placeholder="ulpPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label> <label class="filter-input-label">Periode Tanggal:</label>
<DatePicker /> <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"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Durasi:</label> <label class="filter-input-label">Durasi:</label>
<div class="flex flex-col gap-y-1"> <div class="flex flex-col gap-y-1">
<Select placeholder="Durasi Menit" /> <Select @update:selected="changeDuration($event)" :data="sla" placeholder="Durasi Menit" />
<div class="grid grid-flow-col auto-cols-auto gap-x-1.5"> <div class="flex flex-1 justify-between gap-x-1.5">
<InputWithSuffix /> <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> <small class="flex items-center">s/d</small>
<InputWithSuffix /> <InputWithSuffix @update:minute-value="(value: any) => data.maxDurasiResponseTime = value" @value="data.maxDurasiResponseTime"
:disabled="triggerInput" class="flex flex-1" />
</div> </div>
</div> </div>
</div> </div>
</div>
</template> </template>

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

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

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

@ -1,34 +1,72 @@
<script setup lang="ts"> <script setup lang="ts">
import Select from '@/components/Select.vue' import Select from '@/components/Select.vue';
import DatePicker from '@/components/DatePicker.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> </script>
<template> <template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Distribusi/Wilayah:</label> <div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Distribusi/Wilayah:</label>
<Select placeholder="Semua Distribusi/Wilayah"/> <Select :data="itemsUid" @update:selected="setUid($event)" :placeholder="uidPlaceholder" :selected="uid" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Area:</label>
>Area:</label <Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="up3" :placeholder="up3Placeholder" />
>
<Select placeholder="Semua Area" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Posko:</label>
>Posko:</label <Select @update:selected="setPosko($event)" :data="itemsPosko" :selected="posko"
> :placeholder="poskoPlaceholder" />
<Select placeholder="Semua Posko" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label> <label class="filter-input-label">Periode Tanggal:</label>
<DatePicker /> <DatePicker @update:date-value="(value) => data.periode = value" />
</div> </div>
</div>
</template> </template>

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

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

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

@ -1,38 +1,105 @@
<script setup lang="ts"> <script setup lang="ts">
import Select from '@/components/Select.vue' import Select from '@/components/Select.vue';
import DatePicker from '@/components/DatePicker.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> </script>
<template> <template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<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"/> <Select :data="itemsUid" @update:selected="setUid($event)" :placeholder="uidPlaceholder" :selected="uid" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" /> <Select :data="itemsUp3" @update:selected="setUp3($event)" :placeholder="up3Placeholder" :selected="up3" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Posko:</label> <label class="filter-input-label">Posko:</label>
<Select placeholder="Semua Posko" /> <Select :data="itemsPosko" @update:selected="setPosko($event)" :placeholder="poskoPlaceholder"
:selected="posko" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Media:</label> <label class="filter-input-label">Media:</label>
<Select placeholder="Semua Media" /> <Select :selected="media" @update:selected="setMedia($event)" :placeholder="mediaPlaceholder"
:data="itemsMedia" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label> <label class="filter-input-label">Periode Tanggal:</label>
<DatePicker /> <DatePicker @update:date-value="(value) => (data.periode = value)" />
</div> </div>
</div>
</template> </template>

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

@ -1,18 +1,23 @@
<script setup lang="ts"> <script setup lang="ts">
import Select from '@/components/Select.vue' import Select from '@/components/Select.vue';
import DatePicker from '@/components/DatePicker.vue' import DatePicker from '@/components/DatePicker.vue';
import InputWithFilter from '../InputWithFilter.vue' import InputWithFilter from '../InputWithFilter.vue';
import { ref } from 'vue';
const data = ref({
periode: '',
})
</script> </script>
<template> <template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<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>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit PLN:</label> <label class="filter-input-label">Unit PLN:</label>
<div class="flex flex-col gap-y-1"> <div class="flex flex-col gap-y-1">
<Select placeholder="Pilih Unit" /> <Select placeholder="Pilih Unit" />
@ -24,23 +29,23 @@
</div> </div>
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Status:</label> <label class="filter-input-label">Status:</label>
<Select placeholder="Pilih Status"/> <Select placeholder="Pilih Status" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">SLA:</label>
>SLA:</label
>
<Select placeholder="Pilih Durasi SLA" /> <Select placeholder="Pilih Durasi SLA" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Pencarian:</label> <label class="filter-input-label">Pencarian:</label>
<InputWithFilter placeholder="cari report" :filters="[{id: 1, title: 'Pilih Jenis'}]" /> <InputWithFilter placeholder="cari report" :filters="[{ id: 1, title: 'Pilih Jenis' }]" />
</div> </div>
</div>
</template> </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>

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

@ -1,42 +1,137 @@
<script setup lang="ts"> <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> </script>
<template> <template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Regional:</label> <div class="flex flex-col flex-1 space-y-2">
<label class="filter-input-label">Regional:</label>
<Select placeholder="Semua Regional"/> <Select @update:selected="setRegional($event)" :data="itemsRegional" :placeholder="regionalPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Unit Induk Distribusi/Wilayah:</label> <label class="filter-input-label">Unit Induk Distribusi/Wilayah:</label>
<Select placeholder="Semua Unit Induk Distribusi/Wilayah"/> <Select @update:selected="setUid($event)" :data="itemsUid" :selected="uid" :placeholder="uidPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" /> <Select @update:selected="setUp3($event)" :selected="uppp" :data="itemsUp3" :placeholder="up3Placholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Layanan Pelanggan:</label>
>Unit Layanan Pelanggan:</label
>
<Select placeholder="Semua Unit Layanan Pelanggan" /> <Select @update:selected="setUlp($event)" :data="itemsUlp" :selected="ulp" :placeholder="ulpPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode</label> <label class="filter-input-label">Periode</label>
<div class="grid grid-cols-2 gap-x-2"> <div class="grid grid-cols-2 gap-x-2">
<Select placeholder="Juli" /> <Select @update:selected="setMonth($event)" :data="months" :placeholder="bulanPlaceholder" />
<Select placeholder="2023" /> <Select @update:selected="setYear($event)" :data="years" :placeholder="tahunPlaceholder" />
</div> </div>
</div> </div>
</div>
</template> </template>

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

@ -1,34 +1,88 @@
<script setup lang="ts"> <script setup lang="ts">
import Select from '@/components/Select.vue' import Select from '@/components/Select.vue';
import DatePicker from '@/components/DatePicker.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> </script>
<template> <template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<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"/> <Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" /> <Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="up3" :placeholder="up3Placeholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Layanan Pelanggan:</label>
>Unit Layanan Pelanggan:</label
>
<Select placeholder="Semua Unit Layanan Pelanggan" /> <Select @update:selected="setUlp($event)" :data="itemsUlp" :selected="ulp" :placeholder="ulpPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label> <label class="filter-input-label">Periode Tanggal:</label>
<DatePicker /> <DatePicker @update:date-value="(value) => (data.periode = value)" />
</div> </div>
</div>
</template> </template>

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

@ -1,42 +1,94 @@
<script setup lang="ts"> <script setup lang="ts">
import Select from '@/components/Select.vue' import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.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> </script>
<template> <template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<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"/> <Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" /> <Select @update:selected="setUp3($event)" :data="itemsUp3" :placeholder="up3Placeholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Layanan Pelanggan:</label>
>Unit Layanan Pelanggan:</label
>
<Select placeholder="Semua Unit Layanan Pelanggan" /> <Select @update:selected="setUlp($event)" :data="itemsUlp" :placeholder="ulpPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Jenis Laporan:</label>
>Jenis Laporan:</label
>
<Select placeholder="Laporan Berulang Unit" /> <Select
@update:selected="(value) => (data.jenisLaporan = value)"
:data="jenisLaporan"
:placeholder="'Semua Jenis Laporan'"
/>
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label> <label class="filter-input-label">Periode Tanggal:</label>
<DatePicker /> <DatePicker @update:date-value="(value) => (data.periode = value)" />
</div>
</div> </div>
</template> </template>

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

@ -1,32 +1,86 @@
<script setup lang="ts"> <script setup lang="ts">
import Select from '@/components/Select.vue' import { onMounted, ref, watch } from 'vue';
import DatePicker from '@/components/DatePicker.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> </script>
<template> <template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<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"/> <Select :data="itemsUid" @update:selected="setUid($event)" :placeholder="uidPlaceholder" :selected="uid" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" /> <Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="uppp" :placeholder="uppPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Posko:</label> <label class="filter-input-label">Posko:</label>
<Select placeholder="Semua Posko" /> <Select @update:selected="setPosko($event)" :data="itemsPosko" :selected="posko"
:placeholder="poskoPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label> <label class="filter-input-label">Periode Tanggal:</label>
<DatePicker @update:date-value="(value) => data.periode = value" />
<DatePicker />
</div> </div>
</div>
</template> </template>

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

@ -1,42 +1,98 @@
<script setup lang="ts"> <script setup lang="ts">
import Select from '@/components/Select.vue' import InputNumber from '@/components/Form/InputNumber.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 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> </script>
<template> <template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<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"/> <Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" /> <Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="up3" :placeholder="up3Placeholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Posko:</label> <label class="filter-input-label">Posko:</label>
<Select placeholder="Semua Posko" /> <Select @update:selected="setPosko($event)" :data="itemsPosko" :selected="posko"
:placeholder="poskoPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label> <label class="filter-input-label">Periode Tanggal:</label>
<DatePicker /> <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"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Lapor Ulang:</label> <label class="filter-input-label">Lapor Ulang:</label>
<div class="grid grid-flow-col auto-cols-auto gap-x-1.5"> <div class="flex flex-1 justify-between gap-x-1.5">
<Select placeholder="1" /> <InputNumber :value="data.minJmlLapor" @update:time-value="(value) => (data.minJmlLapor = value)"
class="flex flex-1" />
<small class="flex items-center">s/d</small> <small class="flex items-center">s/d</small>
<Select placeholder="2" /> <InputNumber :value="data.maxJmlLapor" @update:time-value="(value) => (data.maxJmlLapor = value)"
class="flex flex-1" />
</div> </div>
</div> </div>
</div>
</template> </template>

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

@ -1,47 +1,177 @@
<script setup lang="ts"> <script setup lang="ts">
import Select from '@/components/Select.vue' interface SlaOption {
import DatePicker from '@/components/DatePicker.vue' id: number
import InputWithSuffix from '../InputWithSuffix.vue'; 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> </script>
<template> <template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<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"/> <Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" /> <Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="up3" :placeholder="up3Placeholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Posko:</label> <label class="filter-input-label">Posko:</label>
<Select placeholder="Semua Posko" /> <Select @update:selected="setPosko($event)" :data="itemsPosko" :selected="posko"
:placeholder="poskoPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label> <label class="filter-input-label">Periode Tanggal:</label>
<DatePicker /> <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"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Durasi:</label> <label class="filter-input-label">Durasi:</label>
<div class="flex flex-col gap-y-1"> <div class="flex flex-col gap-y-1">
<Select placeholder="Durasi Menit" /> <Select @update:selected="changeDuration($event)" :data="sla" placeholder="Durasi Menit" />
<div class="grid grid-flow-col auto-cols-auto gap-x-1.5"> <div class="flex flex-1 justify-between gap-x-1.5" :class="[isHidden ? 'hidden' : '']">
<InputWithSuffix /> <InputWithSuffix :value="`${data.minTime} Menit`" @update:text="setMin($event)" class="flex flex-1" />
<small class="flex items-center">s/d</small> <small class="flex items-center">s/d</small>
<InputWithSuffix /> <InputWithSuffix :value="`${data.maxTime} Menit`" @update:text="setMax($event)" class="flex flex-1" />
</div> </div>
</div> </div>
</div> </div>
</div>
</template> </template>

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

@ -1,26 +1,65 @@
<script setup lang="ts"> <script setup lang="ts">
import Select from '@/components/Select.vue' import Select from '@/components/Select.vue';
import DatePicker from '@/components/DatePicker.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> </script>
<template> <template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<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"/> <Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" /> <Select @update:selected="setUp3($event)" :data="itemsUp3" :selected="uppp" :placeholder="uppPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label> <label class="filter-input-label">Periode Tanggal:</label>
<DatePicker /> <DatePicker @update:date-value="(value) => (data.periode = value)" />
</div> </div>
</div>
</template> </template>

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

@ -1,39 +1,99 @@
<script setup lang="ts"> <script setup lang="ts">
import Select from '@/components/Select.vue' import Select from '@/components/Select.vue'
import DatePicker from '@/components/DatePicker.vue' import DatePicker from '@/components/DatePicker.vue'
import InlineRadioGroup from '@/components/Form/InlineRadioGroup.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> </script>
<template> <template>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<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"/> <Select @update:selected="setUid($event)" :data="itemsUid" :placeholder="uidPlaceholder" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block" <label class="filter-input-label">Unit Pelaksanaan Pelayanan Pelanggan:</label>
>Unit Pelaksanaan Pelayanan Pelanggan:</label
>
<Select placeholder="Semua Unit Pelaksanaan Pelayanan Pelanggan" /> <Select @update:selected="setUp3($event)" :data="itemsUp3" :placeholder="uppPlaceholder" :selected="uppp" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Posko:</label> <label class="filter-input-label">Posko:</label>
<Select placeholder="Semua Posko" /> <Select @update:selected="setPosko($event)" :data="itemsPosko" :placeholder="poskoPlaceholder"
:selected="posko" />
</div> </div>
<div class="sm:grid sm:grid-cols-2 lg:grid-cols-3 sm:items-center"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Periode Tanggal:</label> <label class="filter-input-label">Periode Tanggal:</label>
<DatePicker /> <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"> <div class="flex flex-col flex-1 space-y-2">
<label class="text-gray-800 font-semibold mb-2 sm:mb-0 block">Group By Kode Unit Distribusi:</label> <label class="filter-input-label">Group By Kode Unit Distribusi:</label>
<InlineRadioGroup :radio-items="[{id: 1, title: 'Tidak', checked: true}, {id: 2, title: 'Ya, Grupkan'}]" /> <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>
</template> </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 Type15 } from '@/components/Form/FiltersType/Type15.vue'
export { default as Type16 } from '@/components/Form/FiltersType/Type16.vue' export { default as Type16 } from '@/components/Form/FiltersType/Type16.vue'
export { default as Type17 } from '@/components/Form/FiltersType/Type17.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> <fieldset>
<div class="space-y-3 sm:flex sm:items-center sm:space-y-0 sm:space-x-5"> <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"> <div v-for="item in radioItems" :key="item.id" class="flex items-center">
<input :id="`${item.id}`" type="radio" name="radio" <input
:checked="item.hasOwnProperty('checked') && item.checked === true" v-model="groupValue"
class="w-4 h-4 border-gray-300 text-primary-500 peer focus:ring-primary-500" /> type="radio"
<label :for="`${item.id}`" class="block ml-3 text-sm font-medium text-gray-700 peer-checked:text-primary-500">{{ name="radio"
item.title }}</label> :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>
</div> </div>
</fieldset> </fieldset>
@ -15,18 +23,32 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { type PropType } from 'vue' import { ref, type PropType, onMounted } from 'vue'
interface Item { interface Item {
id: number; id: number
title: string; title: string
checked?: boolean; checked?: boolean
} }
defineProps({ const onChange = (e: Item) => {
itemSelected.value = e
console.log(e)
emit('update:groupValue', e)
}
const props = defineProps({
radioItems: { radioItems: {
type: Array as PropType<Item[]>, type: Array as PropType<Item[]>,
required: true required: true
} }
}) })
const itemSelected = ref(props.radioItems[0])
const emit = defineEmits(['update:groupValue'])
const groupValue = ref(1)
onMounted(() => {
itemSelected.value = props.radioItems[0]
})
</script> </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"> <script setup lang="ts">
import { PhMagnifyingGlass } from '@phosphor-icons/vue'; import { PhMagnifyingGlass } from '@phosphor-icons/vue'
import { type PropType } from 'vue' import { type PropType } from 'vue'
interface FilterItems { interface FilterItems {
id: number; id: number
title: string; title: string
} }
const props = defineProps({ const props = defineProps({
@ -25,29 +25,43 @@ const props = defineProps({
required: true 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> </script>
<template> <template>
<div class="relative w-full overflow-hidden rounded-lg"> <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" /> <PhMagnifyingGlass size="18" class="text-gray-900" weight="regular" />
</div> </div>
<input <input
@input="setKeyword"
:placeholder="placeholder" :placeholder="placeholder"
:disabled="disabled" :disabled="disabled"
:readonly="readonly" :readonly="readonly"
type="text" 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"> <div class="absolute inset-y-0 right-0 flex items-center">
<label for="filters" class="sr-only">filters</label> <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 <select
@change="setFilter"
id="filters" id="filters"
name="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> </select>
</div> </div>
</div> </div>

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

@ -1,34 +1,58 @@
<script setup lang="ts"> <script setup lang="ts">
const props = defineProps({ import { ref, watch } from 'vue';
const props = defineProps({
placeholder: { placeholder: {
type: String, type: String,
default: "", default: ''
}, },
disabled: { disabled: {
type: Boolean, type: Boolean,
default: false, default: false
}, },
readonly: { readonly: {
type: Boolean, type: Boolean,
default: false, 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> </script>
<template> <template>
<div class="relative w-full overflow-hidden rounded-lg bg-gray-200"> <div class="relative w-full overflow-hidden bg-gray-200 rounded-lg" :class="[props.class]">
<input <input v-model="text" autocomplete="off" type="text" :placeholder="placeholder" :readonly="readonly"
autocomplete="off" inputmode="numeric" pattern="[0-9.]*" :disabled="disabled" @input="handleInput($event)" @blur="handleBlur($event)"
type="text" @focus="handleFocus($event)"
:placeholder="placeholder" 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" />
: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> </div>
</template> </template>

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

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

@ -1,37 +1,37 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref } from 'vue';
const props = defineProps({ const props = defineProps({
type: { type: {
type: String, type: String,
default: "text", default: 'text'
}, },
placeholder: { placeholder: {
type: String, type: String,
default: "", default: ''
}, },
value: { value: {
type: String, type: String,
default: "", default: ''
}, },
disabled: { disabled: {
type: Boolean, type: Boolean,
default: false, default: false
}, },
readonly: { readonly: {
type: Boolean, type: Boolean,
default: false, default: false
}, },
className: { className: {
type: String, type: String,
default: "", default: ''
} }
}) })
const emit = defineEmits(['update:value']) const emit = defineEmits(['update:value'])
const updateValue = (event: Event) => { const updateValue = (event: Event) => {
const value = (event.target as HTMLInputElement).value; const value = (event.target as HTMLInputElement).value
emit('update:value', value) emit('update:value', value)
} }
@ -39,14 +39,17 @@ const inputType = ref(props.type)
const switchInputType = () => { const switchInputType = () => {
inputType.value = inputType.value == 'password' ? 'text' : 'password' inputType.value = inputType.value == 'password' ? 'text' : 'password'
} }
</script> </script>
<template> <template>
<div :class="['relative w-full overflow-hidden rounded-lg bg-gray-50 ', className]"> <div :class="['relative w-full overflow-hidden rounded-lg bg-gray-200 ', className]">
<input autocomplete="off" :type="inputType" :placeholder="placeholder" :value="value" @input="updateValue($event)" <input v-if="!readonly" autocomplete="off" :type="inputType" :placeholder="placeholder" :value="value"
:disabled="disabled" :readonly="readonly" @input="updateValue($event)" :disabled="disabled" :readonly="readonly" :class="[
: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']" /> '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'" <span @click="switchInputType" v-if="type == 'password'"
class="absolute top-0 bottom-0 right-0 mx-3 my-auto cursor-pointer h-fit"> 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" <svg width="20" height="20" viewBox="0 0 20 20"

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

@ -35,7 +35,7 @@ const closeSideBar = () => menu.toggleSidebar()
<template> <template>
<TransitionRoot as="template" :show="menu.sidebarOpen"> <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" <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" enter-to="opacity-100" leave="transition-opacity ease-linear duration-300" leave-from="opacity-100"
leave-to="opacity-0"> leave-to="opacity-0">
@ -86,7 +86,7 @@ const closeSideBar = () => menu.toggleSidebar()
</Dialog> </Dialog>
</TransitionRoot> </TransitionRoot>
<!-- Static sidebar for desktop --> <!-- 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 --> <!-- 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"> <div class="flex flex-row items-center flex-shrink-0 h-16 px-2 bg-primary-50">
<button type="button" <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']" :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" /> aria-hidden="true" />
<span <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 }} {{ item.name }}
</span> </span>

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

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

@ -1,15 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { useAuthStore } from '@/stores/auth' import { useAuthStore } from '@/stores/auth'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import { useCommandPalattesStore } from '@/stores/command' import { useCommandPalattesStore } from '@/stores/command'
import { useMenuStore } from '@/stores/menu' import { useMenuStore } from '@/stores/menu'
import { import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/vue'
Menu,
MenuButton,
MenuItem,
MenuItems,
} from '@headlessui/vue'
import { MagnifyingGlassIcon } from '@heroicons/vue/24/solid' import { MagnifyingGlassIcon } from '@heroicons/vue/24/solid'
import PictureInitial from '@/components/PictureInitial.vue' import PictureInitial from '@/components/PictureInitial.vue'
import { useDialogStore } from '@/stores/dialog' import { useDialogStore } from '@/stores/dialog'
@ -39,14 +33,13 @@ const showDialogLogout = () => {
} }
</script> </script>
<template> <template>
<div class="sticky top-0 z-10 flex flex-shrink-0 h-16 bg-primary-50 md:ml-80"> <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 md:hidden" @click="openSideBar"> <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> <span class="sr-only">Open sidebar</span>
<IconBars3 class="w-6 h-6 fill-gray-600" /> <IconBars3 class="w-6 h-6 fill-gray-600" />
</button> </button>
<RouterLink to="/home" class="flex items-center flex-shrink-0 my-auto ml-2 md:hidden"> <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" /> <img class="w-auto h-11" :src="IconApp" alt="PLN" />
</RouterLink> </RouterLink>
<div class="flex justify-end w-full px-4"> <div class="flex justify-end w-full px-4">
@ -73,25 +66,25 @@ const showDialogLogout = () => {
</div> </div>
<transition enter-active-class="transition duration-100 ease-out" <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" 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-active-class="transition duration-75 ease-in" leave-from-class="transform scale-100 opacity-100"
leave-from-class="transform scale-100 opacity-100" leave-to-class="transform scale-95 opacity-0"> leave-to-class="transform scale-95 opacity-0">
<MenuItems class="container-menu-item"> <MenuItems class="container-menu-item">
<div class="container-menu-profile group"> <div class="container-menu-profile group">
<div class="flex items-center"> <div class="flex items-center">
<div> <div>
<PictureInitial class-name="inline-block" size-class="w-9 h-9" <PictureInitial class-name="inline-block" size-class="w-9 h-9" background-class="bg-secondary-100"
background-class="bg-secondary-100" font-class="text-xs font-normal font-semibold text-primary-500" :name="user.user_name" />
font-class="text-xs font-normal font-semibold text-primary-500"
:name="user.user_name" />
</div> </div>
<div class="ml-3 space-y-1"> <div class="ml-3 space-y-1">
<p class="text-sm font-medium text-primary-50 "> <p class="text-sm font-medium text-primary-50">
{{ user.user_name }} {{ user.user_name }}
</p> </p>
<p class="text-xs font-normal text-primary-50"> <p class="text-xs font-normal text-primary-50">
{{ user.user_access }} {{ user.user_access }}
</p> </p>
<p class="text-xs font-normal border-t border-white text-primary-50">
UID {{ user.user_uid }}
</p>
</div> </div>
</div> </div>
</div> </div>

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