first commit
This commit is contained in:
commit
eb2f504652
32490 changed files with 5731109 additions and 0 deletions
15
src/App.vue
Normal file
15
src/App.vue
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="azay-admin-app">
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition>
|
||||
<component :is="Component" />
|
||||
</transition>
|
||||
</router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
29
src/api/index.ts
Normal file
29
src/api/index.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/**config api */
|
||||
import { ref } from "vue";
|
||||
|
||||
const env = ref<string>(process.env.NODE_ENV || "development");
|
||||
// if (process.env.VUE_APP_TEST) {
|
||||
// env = "test";
|
||||
// }
|
||||
|
||||
const config = ref<any>({
|
||||
development: {
|
||||
// API_URI: "https://localhost:7260/api",
|
||||
API_URI: "https://bma-ehr.frappet.synology.me/api/v1",
|
||||
},
|
||||
test: {
|
||||
MEET_URI: "meet.frappet.com",
|
||||
},
|
||||
production: {
|
||||
// API_URI: "https://localhost:5010",
|
||||
API_URI: `${window.location.protocol}//${window.location.host}/api/v1`,
|
||||
},
|
||||
});
|
||||
|
||||
const API_URI = ref<string>(config.value[env.value].API_URI);
|
||||
|
||||
export default {
|
||||
env: env.value,
|
||||
config: config.value,
|
||||
API_URI: API_URI.value,
|
||||
};
|
||||
8
src/app.config.ts
Normal file
8
src/app.config.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/**ใช้รวมไฟล์ย่อยๆ ของ api แต่ละไฟล์ */
|
||||
|
||||
const API = {
|
||||
};
|
||||
|
||||
export default {
|
||||
API: API,
|
||||
};
|
||||
BIN
src/assets/05_modules.pdf
Normal file
BIN
src/assets/05_modules.pdf
Normal file
Binary file not shown.
BIN
src/assets/avatar_user.jpg
Normal file
BIN
src/assets/avatar_user.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
0
src/assets/base.css
Normal file
0
src/assets/base.css
Normal file
BIN
src/assets/ex_slip.jpeg
Normal file
BIN
src/assets/ex_slip.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
BIN
src/assets/krungthai.png
Normal file
BIN
src/assets/krungthai.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 156 KiB |
BIN
src/assets/logo.png
Normal file
BIN
src/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
1
src/assets/logo.svg
Normal file
1
src/assets/logo.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69" xmlns:v="https://vecta.io/nano"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
||||
|
After Width: | Height: | Size: 308 B |
35
src/assets/main.css
Normal file
35
src/assets/main.css
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* @import './base.css'; */
|
||||
|
||||
/* #app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
a,
|
||||
.green {
|
||||
text-decoration: none;
|
||||
color: hsla(160, 100%, 37%, 1);
|
||||
transition: 0.4s;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
a:hover {
|
||||
background-color: hsla(160, 100%, 37%, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
body {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
} */
|
||||
11
src/assets/orgChartData.ts
Normal file
11
src/assets/orgChartData.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
const chartData = {
|
||||
personID: "", // Unique ID เป็นเลข ID ที่อ้างอิงไปที่ตัวบุคคล
|
||||
name: "-", // ขื่อบุคคล
|
||||
positionName: "-", // ชื่อตำแหน่ง
|
||||
positionNum: "", // เลขที่ประจำตำแหน่งในโครงสร้าง
|
||||
departmentName: "", // ชื่อหน่วยงานที่สังกัด
|
||||
avatar: "", // ภาพถ่าย
|
||||
children: [], // บุคคลอื่น ๆ ที่อยู่ภายใต้คนนี้ มีโครงสร้างเหมือนกัน
|
||||
};
|
||||
|
||||
export default chartData;
|
||||
275
src/assets/structChartData.ts
Normal file
275
src/assets/structChartData.ts
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
/**
|
||||
* ข้อมูลจะเริ่มต้นที่ Root ที่มีเพียงอันเดียว แล้วแตกรากลงมา ชื่อฟิลด์ต่าง ๆ จะพยายามให้เหมือนกับ TreeList ฟิลด์ไหนใช้ชื่อต่างกันก็ระบุมาได้นะว่าใน TreeList ใช้อะไร จะได้ใช้ให้เหมือนกัน
|
||||
* - Object ส่วนที่เป็นหน่วยงานประกอบด้วย
|
||||
* - deptID : Unique ID ของสำนัก/ฝ่าย/กอง เป็น Int หรือ String ก็ได้ ขอแค่ระบุให้ชัด
|
||||
* - departmentName : ชื่อสำนัก/ฝ่าย/กอง
|
||||
* - totalPositionCount : จำนวนตำแหน่งทั้งหมดในหน่วยงาน หรือในส่วนงานย่อย
|
||||
* - totalPositionVacant : จำนวนตำแหน่งว่างทั้งหมดในหน่วยงาน
|
||||
* - นอกจากนั้นในแต่ละหน่วยงานยังมี Object ได้อีก 3 แบบคือ
|
||||
* - heads : เป็น Array ของ Object ที่เก็บตำแหน่งระดับหัวหน้า
|
||||
* - offcier : เป็น Array ของ Object ที่เก็บตำแหน่งระดับเจ้าหน้าที่
|
||||
* - children : เป็น Array ของหน่วยงานย่อย ซึ่ง Root ของ children ต้องเป็น Object ของหน่วยงานเสมอ
|
||||
* - Object ส่วนที่เป็นตำแหน่งประกอบด้วย
|
||||
* - positionID : Unique ID ของตำแหน่งประเภทนั้น เงื่อนไขเหมือน deptID
|
||||
* - positionName : ชื่อตำแหน่ง
|
||||
* - positionNum : เลขที่ประจำตำแหน่ง เช่น กทข.
|
||||
* - totalPositionCount : จำนวนตำแหน่งทั้งหมด
|
||||
* - totalPositionVacant : จำนวนตำแหน่งว่างทั้งหมด
|
||||
*/
|
||||
const chartData = {
|
||||
// root ของข้อมูลเป็น Object (ไม่ใช่ Array แบบ TreeList)
|
||||
deptID: 1, // Unique ID ของสำนัก/ฝ่าย/กอง (ถ้ามี?)
|
||||
departmentName: "สำนักงานเลขานุการผู้ว่าราชการกรุงเทพมหานคร", // ชื่อสำนัก/ฝ่าย/กอง
|
||||
totalPositionCount: 75, // จำนวนตำแหน่งทั้งหมดในหน่วยงาน
|
||||
totalPositionVacant: 2, // จำนวนตำแหน่งว่างทั้งหมดในหน่วยงาน
|
||||
heads: [
|
||||
// Array ของผู้บริหารในหน่วยงานนั้น ๆ (ผู้อำนวยการ/หัวหน้า)
|
||||
{
|
||||
positionID: 2, // Unique ID ของตำแหน่งประเภทนั้น (ถ้ามี?)
|
||||
positionName: "ผู้อำนวยการสูง", // ชื่อตำแหน่ง
|
||||
positionNum: "(หัวหน้าสำนักงาน)", // เลขที่ประจำตำแหน่ง (ถ้ามี) เช่นพวก กทข.
|
||||
totalPositionCount: 1, // จำนวนตำแหน่งทั้งหมด
|
||||
totalPositionVacant: 0, // จำนวนตำแหน่งว่างทั้งหมด
|
||||
},
|
||||
],
|
||||
officer: [
|
||||
// Array ของเจ้าหน้าที่ในหน่วยงาน (รายการตำแหน่งในหน่วยงานที่ขึ้นตรงกับ deptID นั้น ๆ)
|
||||
],
|
||||
children: [
|
||||
// Array ของหน่วยงานย่อย เช่น ฝ่าย กอง
|
||||
{
|
||||
// โครงสร้างที่เหลือจะเหมือนกับส่วน Root ทุกอย่าง คือแต่ละหน่วยงานย่อย มี heads ไว้ระบุหัวหน้า ผู้อำนวยการ มี Officer ไว้ระบุรายการตำแหน่งในหน่วยงาน มี Children ไว้ระบุหน่วยงานย่อย
|
||||
deptID: 3,
|
||||
departmentName: "ฝ่ายบริหารทั่วไป",
|
||||
totalPositionCount: 14,
|
||||
totalPositionVacant: 0,
|
||||
heads: [
|
||||
{
|
||||
positionID: 2,
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "ชพ. (หัวหน้าฝ่าย)",
|
||||
totalPositionCount: 1,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
],
|
||||
officer: [
|
||||
{
|
||||
positionID: 3,
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "ปก./ชก",
|
||||
totalPositionCount: 1,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
{
|
||||
positionID: 4,
|
||||
positionName: "นักทรัพยากรบุคคล",
|
||||
positionNum: "ปก./ชก.",
|
||||
totalPositionCount: 1,
|
||||
totalPositionVacnt: 0,
|
||||
},
|
||||
{
|
||||
positionID: 5,
|
||||
positionName: "นักวิชาการเงินและบัญชี",
|
||||
positionNum: "ปก./ชก.",
|
||||
totalPositionCount: 2,
|
||||
totalPositionVacnt: 0,
|
||||
},
|
||||
{
|
||||
positionID: 6,
|
||||
positionName: "นักวิชาการพัสดุ",
|
||||
positionNum: "ปก./ชก.",
|
||||
totalPositionCount: 1,
|
||||
totalPositionVacnt: 0,
|
||||
},
|
||||
{
|
||||
positionID: 7,
|
||||
positionName: "เจ้าพนักงานการเงินและบัญชี",
|
||||
positionNum: "ปง./ชง.",
|
||||
totalPositionCount: 3,
|
||||
totalPositionVacnt: 0,
|
||||
},
|
||||
{
|
||||
positionID: 8,
|
||||
positionName: "เจ้าพนักงานพัสดุ",
|
||||
positionNum: "ปง./ชง.",
|
||||
totalPositionCount: 1,
|
||||
totalPositionVacnt: 0,
|
||||
},
|
||||
{
|
||||
positionID: 9,
|
||||
positionName: "เจ้าพนักงานธุรการ",
|
||||
positionNum: "ปง./ชง.",
|
||||
totalPositionCount: 4,
|
||||
totalPositionVacnt: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
deptID: 4,
|
||||
departmentName: "ส่วนประสานนโยบาย",
|
||||
totalPositionCount: 15,
|
||||
totalPositionVacant: 0,
|
||||
heads: [
|
||||
{
|
||||
positionID: 10,
|
||||
positionName: "ผู้อำนวยการต้น",
|
||||
positionNum: "(ผู้อำนวยการส่วน)",
|
||||
totalPositionCount: 1,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
],
|
||||
children: [
|
||||
{
|
||||
deptID: 11,
|
||||
departmentName: "กลุ่มงานประชุม",
|
||||
totalPositionCount: 6,
|
||||
totalPositionVacant: 0,
|
||||
heads: [
|
||||
{
|
||||
positionID: 11,
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "ชพ. (หัวหน้ากลุ่มงาน)",
|
||||
totalPositionCount: 1,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
],
|
||||
officer: [
|
||||
{
|
||||
positionID: 12,
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "ปก./ชก.",
|
||||
totalPositionCount: 4,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
{
|
||||
positionID: 13,
|
||||
positionName: "เจ้าพนักงานธุรการ",
|
||||
positionNum: "ปง./ชง.",
|
||||
totalPositionCount: 1,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
deptID: 12,
|
||||
departmentName: "กลุ่มงานการเมืองและประสานนโยบาย",
|
||||
totalPositionCount: 8,
|
||||
totalPositionVacant: 0,
|
||||
heads: [
|
||||
{
|
||||
positionID: 14,
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "ชพ. (หัวหน้ากลุ่มงาน)",
|
||||
totalPositionCount: 1,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
],
|
||||
officer: [
|
||||
{
|
||||
positionID: 15,
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "ปก./ชก.",
|
||||
totalPositionCount: 4,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
{
|
||||
positionID: 16,
|
||||
positionName: "เจ้าพนักงานสถิติ",
|
||||
positionNum: "ปง./ชง.",
|
||||
totalPositionCount: 1,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
{
|
||||
positionID: 17,
|
||||
positionName: "เจ้าพนักงานธุรการ",
|
||||
positionNum: "ปง./ชง.",
|
||||
totalPositionCount: 2,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
deptID: 14,
|
||||
departmentName: "ส่วนเรื่องราวร้องทุกข์",
|
||||
totalPositionCount: 15,
|
||||
totalPositionVacant: 0,
|
||||
heads: [
|
||||
{
|
||||
positionID: 18,
|
||||
positionName: "ผู้อำนวยการต้น",
|
||||
positionNum: "(ผู้อำนวยการส่วน)",
|
||||
totalPositionCount: 1,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
],
|
||||
children: [
|
||||
{
|
||||
deptID: 15,
|
||||
departmentName: "กลุ่มงานรับเรื่องราวร้องทุกข์",
|
||||
totalPositionCount: 7,
|
||||
totalPositionVacant: 0,
|
||||
heads: [
|
||||
{
|
||||
positionID: 19,
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "ชพ. (หัวหน้ากลุ่มงาน)",
|
||||
totalPositionCount: 1,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
],
|
||||
officer: [
|
||||
{
|
||||
positionID: 20,
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "ปก./ชก.",
|
||||
totalPositionCount: 4,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
{
|
||||
positionID: 21,
|
||||
positionName: "เจ้าพนักงานธุรการ",
|
||||
positionNum: "ปง./ชง.",
|
||||
totalPositionCount: 2,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
deptID: 16,
|
||||
departmentName: "กลุ่มงานตรวจสอบ ติดตามและประมวลผล",
|
||||
totalPositionCount: 7,
|
||||
totalPositionVacant: 0,
|
||||
heads: [
|
||||
{
|
||||
positionID: 22,
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "ชพ. (หัวหน้ากลุ่มงาน)",
|
||||
totalPositionCount: 1,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
],
|
||||
officer: [
|
||||
{
|
||||
positionID: 23,
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "ปก./ชก.",
|
||||
totalPositionCount: 4,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
{
|
||||
positionID: 24,
|
||||
positionName: "เจ้าพนักงานธุรการ",
|
||||
positionNum: "ปง./ชง.",
|
||||
totalPositionCount: 2,
|
||||
totalPositionVacant: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default chartData;
|
||||
8321
src/assets/tree.json
Normal file
8321
src/assets/tree.json
Normal file
File diff suppressed because it is too large
Load diff
90
src/components/CustomDialog.vue
Normal file
90
src/components/CustomDialog.vue
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
<template>
|
||||
<q-dialog ref="dialogRef" @hide="onDialogHide" persistent>
|
||||
<q-card class="q-pa-sm">
|
||||
<q-card-section class="row">
|
||||
<div class="q-pr-md">
|
||||
<q-avatar
|
||||
:icon="icon"
|
||||
size="lg"
|
||||
font-size="25px"
|
||||
color="blue-1"
|
||||
:text-color="color"
|
||||
/>
|
||||
</div>
|
||||
<div class="col text-dark">
|
||||
<span class="text-bold">{{ title }}</span>
|
||||
<br />
|
||||
<span>{{ message }}</span>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions
|
||||
align="right"
|
||||
class="bg-white text-teal"
|
||||
v-if="onlycancel"
|
||||
>
|
||||
<q-btn label="ตกลง" flat color="grey-8" @click="onDialogCancel" />
|
||||
<!-- <q-btn :label="textOk" :color="color" @click="onOKClick" /> -->
|
||||
</q-card-actions>
|
||||
<q-card-actions align="right" class="bg-white text-teal" v-else>
|
||||
<q-btn label="ยกเลิก" flat color="grey-8" @click="onDialogCancel" />
|
||||
<q-btn :label="textOk" :color="color" @click="onOKClick" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useDialogPluginComponent } from "quasar";
|
||||
|
||||
const props = defineProps({
|
||||
color: {
|
||||
type: String,
|
||||
default: "primary",
|
||||
},
|
||||
textOk: {
|
||||
type: String,
|
||||
default: "ตกลง",
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: "หัวข้อ?",
|
||||
},
|
||||
message: {
|
||||
type: String,
|
||||
default: "ข้อความ",
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: "question_mark",
|
||||
},
|
||||
onlycancel: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
defineEmits([
|
||||
// REQUIRED; need to specify some events that your
|
||||
// component will emit through useDialogPluginComponent()
|
||||
...useDialogPluginComponent.emits,
|
||||
]);
|
||||
|
||||
const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
|
||||
useDialogPluginComponent();
|
||||
// dialogRef - Vue ref to be applied to QDialog
|
||||
// onDialogHide - Function to be used as handler for @hide on QDialog
|
||||
// onDialogOK - Function to call to settle dialog with "ok" outcome
|
||||
// example: onDialogOK() - no payload
|
||||
// example: onDialogOK({ /*...*/ }) - with payload
|
||||
// onDialogCancel - Function to call to settle dialog with "cancel" outcome
|
||||
|
||||
// this is part of our example (so not required)
|
||||
function onOKClick() {
|
||||
// on OK, it is REQUIRED to
|
||||
// call onDialogOK (with optional payload)
|
||||
onDialogOK();
|
||||
// or with payload: onDialogOK({ ... })
|
||||
// ...and it will also hide the dialog automatically
|
||||
}
|
||||
</script>
|
||||
24
src/components/FullLoader.vue
Normal file
24
src/components/FullLoader.vue
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<!-- แสดง ui การโหลด -->
|
||||
<template>
|
||||
<q-inner-loading :showing="loaderVisibility" class="loader">
|
||||
<q-spinner-cube size="80px" color="primary" />
|
||||
</q-inner-loading>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { watch, ref } from "vue";
|
||||
const props = defineProps({
|
||||
visibility: Boolean,
|
||||
});
|
||||
|
||||
const loaderVisibility = ref<boolean>(props.visibility);
|
||||
|
||||
watch(props, (count, prevCount) => {
|
||||
loaderVisibility.value = props.visibility;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="sass">
|
||||
.loader
|
||||
z-index: 1000
|
||||
</style>
|
||||
19
src/components/Selector.vue
Normal file
19
src/components/Selector.vue
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<template>
|
||||
<q-select v-bind="attrs">
|
||||
<template v-for="(_, slot) in slots" v-slot:[slot]="scope">
|
||||
<slot :name="slot" v-bind="scope || {}" />
|
||||
</template>
|
||||
<template v-slot:no-option>
|
||||
<q-item>
|
||||
<q-item-section class="text-black">
|
||||
ไม่พบข้อมูลที่ค้นหา
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
</q-select>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, useAttrs, useSlots } from "vue";
|
||||
const attrs = ref<any>(useAttrs());
|
||||
const slots = ref<any>(useSlots());
|
||||
</script>
|
||||
88
src/components/Table.vue
Normal file
88
src/components/Table.vue
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
<template>
|
||||
<q-table
|
||||
ref="table"
|
||||
flat
|
||||
bordered
|
||||
class="custom-header-table"
|
||||
v-bind="attrs"
|
||||
virtual-scroll
|
||||
:virtual-scroll-sticky-size-start="48"
|
||||
dense
|
||||
:pagination-label="paginationLabel"
|
||||
v-model:pagination="pagination"
|
||||
>
|
||||
<template v-slot:pagination="scope">
|
||||
<q-pagination
|
||||
v-model="pagination.page"
|
||||
active-color="primary"
|
||||
color="dark"
|
||||
:max="scope.pagesNumber"
|
||||
:max-pages="5"
|
||||
size="sm"
|
||||
boundary-links
|
||||
direction-links
|
||||
></q-pagination>
|
||||
</template>
|
||||
|
||||
<template v-for="(_, slot) in slots" v-slot:[slot]="scope">
|
||||
<slot :name="slot" v-bind="scope || {}" />
|
||||
</template>
|
||||
</q-table>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, useAttrs, useSlots } from "vue";
|
||||
const attrs = ref<any>(useAttrs());
|
||||
const slots = ref<any>(useSlots());
|
||||
|
||||
const props = defineProps({
|
||||
paging: {
|
||||
type: Boolean,
|
||||
defualt: false,
|
||||
},
|
||||
});
|
||||
|
||||
const pagination = ref({
|
||||
sortBy: "desc",
|
||||
descending: false,
|
||||
page: 1,
|
||||
rowsPerPage: 10,
|
||||
});
|
||||
|
||||
const paginationLabel = (start: string, end: string, total: string) => {
|
||||
if (props.paging == true)
|
||||
return " " + start + " ใน " + end + " จากจำนวน " + total + " รายการ";
|
||||
else return start + "-" + end + " ใน " + total;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.icon-color {
|
||||
color: #4154b3;
|
||||
}
|
||||
.custom-header-table {
|
||||
height: auto;
|
||||
.q-table tr:nth-child(odd) td {
|
||||
background: white;
|
||||
}
|
||||
.q-table tr:nth-child(even) td {
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
.q-table thead tr {
|
||||
background: #ecebeb;
|
||||
}
|
||||
|
||||
.q-table thead tr th {
|
||||
position: sticky;
|
||||
z-index: 1;
|
||||
}
|
||||
/* this will be the loading indicator */
|
||||
.q-table thead tr:last-child th {
|
||||
/* height of all previous header rows */
|
||||
top: 48px;
|
||||
}
|
||||
.q-table thead tr:first-child th {
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
570
src/components/TableView.vue
Normal file
570
src/components/TableView.vue
Normal file
|
|
@ -0,0 +1,570 @@
|
|||
<template>
|
||||
<div class="q-px-md q-pb-md">
|
||||
<!-- header บน table มี ค้นหา แสดงคอลัมน์ ปุ่มแก้ไข เพิ่ม เผยแพร่ข้อมูล ยกเลิก (status nornmalData false) -->
|
||||
<div class="col-12 row q-py-sm" v-if="nornmalData == false">
|
||||
<q-btn
|
||||
v-if="!editvisible == true && publicNoBtn == false"
|
||||
flat
|
||||
round
|
||||
:disabled="editvisible == true"
|
||||
:color="editvisible == true ? 'grey-7' : 'primary'"
|
||||
@click="edit"
|
||||
icon="mdi-pencil-outline"
|
||||
>
|
||||
<q-tooltip>แก้ไขข้อมูล</q-tooltip>
|
||||
</q-btn>
|
||||
<!-- ยกเลิก แสดงเมื่อ กดปุ่มแก้ไข -->
|
||||
<q-btn
|
||||
v-else
|
||||
flat
|
||||
round
|
||||
:disabled="editvisible == false"
|
||||
:outline="editvisible == false"
|
||||
:color="editvisible == false ? 'grey-7' : 'red'"
|
||||
@click="cancel()"
|
||||
icon="mdi-undo"
|
||||
>
|
||||
<q-tooltip>ยกเลิก</q-tooltip>
|
||||
</q-btn>
|
||||
<!-- <q-separator vertical /> -->
|
||||
<div class="q-px-sm">
|
||||
<q-btn
|
||||
flat
|
||||
round
|
||||
:disabled="editvisible == false"
|
||||
:color="editvisible == false ? 'grey-7' : 'add'"
|
||||
@click="add"
|
||||
icon="mdi-plus"
|
||||
>
|
||||
<q-tooltip>เพิ่มข้อมูล</q-tooltip>
|
||||
</q-btn>
|
||||
|
||||
<!-- บันทึกร่าง แสดงเมื่อ กดปุ่มแก้ไข ข้อมูลมีการเป็นแปลงหรือ ยังไม่เผยแพร่ข้อมูล -->
|
||||
<q-btn
|
||||
flat
|
||||
round
|
||||
:disabled="!(editvisible == true && updateData == true)"
|
||||
:color="
|
||||
!(editvisible == true && updateData == true) ? 'grey-7' : 'public'
|
||||
"
|
||||
@click="checkSave"
|
||||
v-if="saveNoDraft == false"
|
||||
icon="mdi-content-save-outline"
|
||||
>
|
||||
<q-tooltip>บันทึกร่าง</q-tooltip>
|
||||
</q-btn>
|
||||
<!-- ลบบันทึกร่าง แสดงเมื่อ บันทึกร่างแล้ว -->
|
||||
<q-btn
|
||||
flat
|
||||
round
|
||||
:disabled="publicData == true"
|
||||
:color="publicData == true ? 'grey-7' : 'deep-orange'"
|
||||
@click="DeleteModal"
|
||||
icon="mdi-file-remove-outline"
|
||||
v-if="publicNoBtn == false"
|
||||
>
|
||||
<q-tooltip>ลบบันทึกร่าง</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
|
||||
<!-- เผยแพร่ -->
|
||||
<q-btn
|
||||
flat
|
||||
round
|
||||
:disabled="!(publicData == false || updateData == true)"
|
||||
:color="
|
||||
!(publicData == false || updateData == true) ? 'grey-7' : 'public'
|
||||
"
|
||||
@click="publishModal"
|
||||
icon="mdi-cloud-upload-outline"
|
||||
v-if="publicNoBtn == false"
|
||||
>
|
||||
<q-tooltip>เผยแพร่</q-tooltip>
|
||||
</q-btn>
|
||||
<div class="items-center" style="display: flex">
|
||||
<div
|
||||
class="row items-center"
|
||||
style="display: flex"
|
||||
v-if="publicData == false && publicNoBtn == false"
|
||||
>
|
||||
<div class="text-public text-body2 text-weight-medium q-px-sm">
|
||||
ข้อมูลยังไม่เผยแพร่
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<q-space />
|
||||
<div class="items-center" style="display: flex">
|
||||
<!-- ข้อความสถานะเผยแพร่ โดยใช้ parameter publicData เป็นตัวกำหนดข้อความ -->
|
||||
<!-- <div class="row items-center" style="display: flex" v-if="publicData == true">
|
||||
<q-icon cener size="20px" name="label_important" class="icon-color" />
|
||||
<div class="text-size">ข้อมูลเผยแพร่แล้ว</div>
|
||||
</div> -->
|
||||
<div
|
||||
class="row items-center"
|
||||
style="display: flex"
|
||||
v-if="publicData == false && publicNoBtn == false"
|
||||
>
|
||||
<!-- <q-icon cener size="20px" name="label_important" color="amber" />
|
||||
<div class="text-grey-7 text-body2 text-weight-medium q-px-sm">
|
||||
ข้อมูลยังไม่เผยแพร่
|
||||
</div> -->
|
||||
</div>
|
||||
<!-- ค้นหาข้อความใน table -->
|
||||
<q-input
|
||||
standout
|
||||
dense
|
||||
:model-value="inputfilter"
|
||||
ref="filterRef"
|
||||
@update:model-value="updateInput"
|
||||
outlined
|
||||
debounce="300"
|
||||
placeholder="ค้นหา"
|
||||
style="max-width: 200px"
|
||||
class="q-ml-sm"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<q-icon v-if="inputfilter == ''" name="search" />
|
||||
<q-icon
|
||||
v-if="inputfilter !== ''"
|
||||
name="clear"
|
||||
class="cursor-pointer"
|
||||
@click="resetFilter"
|
||||
/>
|
||||
</template>
|
||||
</q-input>
|
||||
<!-- แสดงคอลัมน์ใน table -->
|
||||
<q-select
|
||||
:model-value="inputvisible"
|
||||
@update:model-value="updateVisible"
|
||||
:display-value="$q.lang.table.columns"
|
||||
multiple
|
||||
outlined
|
||||
dense
|
||||
:options="attrs.columns"
|
||||
options-dense
|
||||
option-value="name"
|
||||
map-options
|
||||
emit-value
|
||||
style="min-width: 150px"
|
||||
class="gt-xs q-ml-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- header บน table มี ค้นหา แสดงคอลัมน์ (status nornmalData true) -->
|
||||
<div class="col-12 row q-py-sm items-center" v-if="nornmalData == true">
|
||||
<span class="text-subtitle1">{{ titleText }}</span>
|
||||
<!-- <q-select
|
||||
:model-value="inputvisibleFilter"
|
||||
:options="optionsFilter"
|
||||
style="min-width: 150px"
|
||||
class="gt-xs q-ml-sm"
|
||||
/> -->
|
||||
|
||||
<q-select
|
||||
dense
|
||||
outlined
|
||||
:model-value="inputvisibleFilter"
|
||||
:options="optionsFilter"
|
||||
class="col-xs-12 col-sm-4 col-md-3"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
map-options
|
||||
emit-value
|
||||
@update:model-value="updateVisibleFilter"
|
||||
v-if="optionsFilter != undefined && optionsFilter.length > 0"
|
||||
/>
|
||||
|
||||
<q-space />
|
||||
<div class="items-center" style="display: flex">
|
||||
<!-- ค้นหาข้อความใน table -->
|
||||
<q-input
|
||||
standout
|
||||
dense
|
||||
:model-value="inputfilter"
|
||||
ref="filterRef"
|
||||
@update:model-value="updateInput"
|
||||
outlined
|
||||
debounce="300"
|
||||
placeholder="ค้นหา"
|
||||
style="max-width: 200px"
|
||||
class="q-ml-sm"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<q-icon v-if="inputfilter == ''" name="search" />
|
||||
<q-icon
|
||||
v-if="inputfilter !== ''"
|
||||
name="clear"
|
||||
class="cursor-pointer"
|
||||
@click="resetFilter"
|
||||
/>
|
||||
</template>
|
||||
</q-input>
|
||||
<!-- แสดงคอลัมน์ใน table -->
|
||||
<q-select
|
||||
:model-value="inputvisible"
|
||||
@update:model-value="updateVisible"
|
||||
:display-value="$q.lang.table.columns"
|
||||
multiple
|
||||
outlined
|
||||
dense
|
||||
:options="attrs.columns"
|
||||
options-dense
|
||||
option-value="name"
|
||||
map-options
|
||||
emit-value
|
||||
style="min-width: 150px"
|
||||
class="gt-xs q-ml-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<q-table
|
||||
ref="table"
|
||||
flat
|
||||
bordered
|
||||
class="custom-header-table"
|
||||
v-bind="attrs"
|
||||
virtual-scroll
|
||||
:virtual-scroll-sticky-size-start="48"
|
||||
dense
|
||||
:pagination-label="paginationLabel"
|
||||
v-model:pagination="pagination"
|
||||
>
|
||||
<!-- :rows-per-page-options="paging == true ? [25, 50, 100, 500] : []" -->
|
||||
<!-- :rows-per-page-options="[0]" -->
|
||||
<template v-slot:header="props">
|
||||
<q-tr :props="props">
|
||||
<q-th auto-width v-if="boss == true" />
|
||||
<q-th v-for="col in props.cols" :key="col.name" :props="props">
|
||||
<span class="text-weight-medium">{{ col.label }}</span>
|
||||
</q-th>
|
||||
<q-th
|
||||
auto-width
|
||||
v-if="
|
||||
editvisible == true || nextPageVisible == true || history == true
|
||||
"
|
||||
/>
|
||||
</q-tr>
|
||||
</template>
|
||||
<template v-slot:pagination="scope">
|
||||
<q-pagination
|
||||
v-model="pagination.page"
|
||||
active-color="primary"
|
||||
color="dark"
|
||||
:max="scope.pagesNumber"
|
||||
:max-pages="5"
|
||||
size="sm"
|
||||
boundary-links
|
||||
direction-links
|
||||
></q-pagination>
|
||||
</template>
|
||||
<!-- สำหรับเรียกใช้ template ตัวข้างนอก -->
|
||||
<template #body="props">
|
||||
<slot v-bind="props" name="columns"></slot>
|
||||
</template>
|
||||
</q-table>
|
||||
</div>
|
||||
<!-- ข้อมูลการเผยแพร่ข้อมูล -->
|
||||
<!-- <notifyPublishDraft v-model:showModal="modalPublish" :ok="publish" /> -->
|
||||
<!-- <q-dialog v-model="modalPublish" persistent>
|
||||
<q-card class="q-pa-sm">
|
||||
<q-card-section class="row">
|
||||
<div class="q-pr-md">
|
||||
<q-avatar
|
||||
icon="public"
|
||||
size="lg"
|
||||
font-size="25px"
|
||||
color="blue-1"
|
||||
text-color="public"
|
||||
/>
|
||||
</div>
|
||||
<div class="col text-dark">
|
||||
<span class="text-bold">ต้องการเผยแพร่ข้อมูลนี้หรือไม่?</span>
|
||||
<br />
|
||||
<span>ข้อมูลที่กำลังถูกเผยแพร่นี้จะมีผลใช้งานทันที</span>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right" class="bg-white text-teal">
|
||||
<q-btn label="ยกเลิก" flat color="grey-8" v-close-popup />
|
||||
<q-btn
|
||||
label="เผยแพร่"
|
||||
color="public"
|
||||
@click="publish()"
|
||||
v-close-popup
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog> -->
|
||||
|
||||
<!-- ข้อมูลการลบเผยแพร่ข้อมูล -->
|
||||
<!-- <notifyDeleteDraft v-model:showModal="modalDelete" :ok="deleted" /> -->
|
||||
<!-- <q-dialog v-model="modalDelete" persistent>
|
||||
<q-card class="q-pa-sm">
|
||||
<q-card-section class="row">
|
||||
<div class="q-pr-md">
|
||||
<q-avatar
|
||||
icon="mdi-file-remove-outline"
|
||||
size="lg"
|
||||
font-size="25px"
|
||||
color="red-1"
|
||||
text-color="deep-orange"
|
||||
/>
|
||||
</div>
|
||||
<div class="col text-dark">
|
||||
<span class="text-bold">ต้องการลบข้อมูลบันทึกร่างนี้หรือไม่?</span>
|
||||
<br />
|
||||
<span>ข้อมูลบันทึกร่างที่กำลังถูกลบนี้จะมีผลใช้งานทันที</span>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right" class="bg-white text-teal">
|
||||
<q-btn label="ยกเลิก" flat color="grey-8" v-close-popup />
|
||||
<q-btn label="ลบบันทึก" color="red" @click="deleted()" v-close-popup />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog> -->
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, useAttrs, computed } from "vue";
|
||||
import { useCounterMixin } from "@/stores/mixin";
|
||||
import { useQuasar } from "quasar";
|
||||
|
||||
const $q = useQuasar();
|
||||
const mixin = useCounterMixin(); //เรียกฟังก์ชันกลาง
|
||||
const { dialogMessage } = mixin;
|
||||
const rows = ref<any>([]);
|
||||
const attrs = ref<any>(useAttrs());
|
||||
const table = ref<any>(null);
|
||||
const filterRef = ref<any>(null);
|
||||
const modalPublish = ref<boolean>(false);
|
||||
const modalDelete = ref<boolean>(false);
|
||||
|
||||
const pagination = ref({
|
||||
sortBy: "desc",
|
||||
descending: false,
|
||||
page: 1,
|
||||
rowsPerPage: 10,
|
||||
});
|
||||
|
||||
const pagesNumber = computed(() => {
|
||||
return Math.ceil(rows.value.length / pagination.value.rowsPerPage);
|
||||
});
|
||||
|
||||
const paginationLabel = (start: string, end: string, total: string) => {
|
||||
if (props.paging == true)
|
||||
return " " + start + " ใน " + end + " จากจำนวน " + total + " รายการ";
|
||||
else return start + "-" + end + " ใน " + total;
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
inputfilter: String,
|
||||
inputvisible: Array,
|
||||
inputvisibleFilter: String,
|
||||
editvisible: Boolean,
|
||||
titleText: String,
|
||||
optionsFilter: {
|
||||
type: Array,
|
||||
defualt: [],
|
||||
},
|
||||
boss: {
|
||||
type: Boolean,
|
||||
defualt: false,
|
||||
},
|
||||
saveNoDraft: {
|
||||
type: Boolean,
|
||||
defualt: false,
|
||||
},
|
||||
history: {
|
||||
type: Boolean,
|
||||
defualt: false,
|
||||
},
|
||||
paging: {
|
||||
type: Boolean,
|
||||
defualt: false,
|
||||
},
|
||||
nornmalData: {
|
||||
type: Boolean,
|
||||
defualt: false,
|
||||
},
|
||||
refreshData: {
|
||||
type: Boolean,
|
||||
defualt: false,
|
||||
},
|
||||
nextPageVisible: {
|
||||
type: Boolean,
|
||||
defualt: false,
|
||||
},
|
||||
publicData: {
|
||||
type: Boolean,
|
||||
defualt: true,
|
||||
required: false,
|
||||
},
|
||||
updateData: {
|
||||
type: Boolean,
|
||||
defualt: true,
|
||||
required: false,
|
||||
},
|
||||
publicNoBtn: {
|
||||
type: Boolean,
|
||||
defualt: false,
|
||||
},
|
||||
add: {
|
||||
type: Function,
|
||||
default: () => console.log("not function"),
|
||||
},
|
||||
edit: {
|
||||
type: Function,
|
||||
default: () => console.log("not function"),
|
||||
},
|
||||
save: {
|
||||
type: Function,
|
||||
default: () => console.log("not function"),
|
||||
},
|
||||
deleted: {
|
||||
type: Function,
|
||||
default: () => console.log("not function"),
|
||||
},
|
||||
cancel: {
|
||||
type: Function,
|
||||
default: () => console.log("not function"),
|
||||
},
|
||||
publish: {
|
||||
type: Function,
|
||||
default: () => console.log("not function"),
|
||||
},
|
||||
validate: {
|
||||
type: Function,
|
||||
default: () => console.log("not function"),
|
||||
},
|
||||
});
|
||||
const initialPagination = ref<any>({
|
||||
// descending: false,
|
||||
rowsPerPage: props.paging == true ? 25 : 0,
|
||||
});
|
||||
|
||||
const emit = defineEmits([
|
||||
"update:inputfilter",
|
||||
"update:inputvisible",
|
||||
"update:editvisible",
|
||||
"update:titleText",
|
||||
"update:inputvisibleFilter",
|
||||
]);
|
||||
|
||||
const updateEdit = (value: any) => {
|
||||
emit("update:editvisible", value);
|
||||
};
|
||||
const updateInput = (value: any) => {
|
||||
emit("update:inputfilter", value);
|
||||
};
|
||||
const updateVisible = (value: any) => {
|
||||
emit("update:inputvisible", value);
|
||||
};
|
||||
const updateVisibleFilter = (value: any) => {
|
||||
emit("update:inputvisibleFilter", value);
|
||||
};
|
||||
|
||||
const checkSave = () => {
|
||||
props.validate();
|
||||
props.save();
|
||||
// if (myForm.value !== null) {
|
||||
// myForm.value.validate().then((success) => {
|
||||
// if (success) {
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
};
|
||||
|
||||
const publishModal = () => {
|
||||
props.validate();
|
||||
const filter = attrs.value.rows.filter((r: any) => r.name == "");
|
||||
|
||||
if (filter.length == 0 || attrs.value.rows.length == 0) {
|
||||
// modalPublish.value = true;
|
||||
dialogMessage(
|
||||
$q,
|
||||
"ต้องการเผยแพร่ข้อมูลนี้หรือไม่?",
|
||||
"ข้อมูลที่กำลังถูกเผยแพร่นี้จะมีผลใช้งานทันที",
|
||||
"public",
|
||||
"เผยแพร่",
|
||||
"public",
|
||||
props.publish,
|
||||
undefined
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const DeleteModal = () => {
|
||||
// modalDelete.value = true;
|
||||
dialogMessage(
|
||||
$q,
|
||||
"ต้องการลบข้อมูลบันทึกร่างนี้หรือไม่?",
|
||||
"ข้อมูลบันทึกร่างที่กำลังถูกลบนี้จะมีผลใช้งานทันที",
|
||||
"mdi-file-remove-outline",
|
||||
"ลบบันทึก",
|
||||
"red",
|
||||
props.deleted,
|
||||
undefined
|
||||
);
|
||||
};
|
||||
|
||||
const edit = async () => {
|
||||
updateEdit(!props.editvisible);
|
||||
props.edit();
|
||||
};
|
||||
|
||||
const add = async () => {
|
||||
// if (myForm.value !== null) {
|
||||
// myForm.value.validate();
|
||||
// }
|
||||
props.validate();
|
||||
props.add();
|
||||
await table.value.lastPage();
|
||||
await table.value.scrollTo(attrs.value.rows.length - 1);
|
||||
};
|
||||
|
||||
const deleted = async () => {
|
||||
// const deletedF = () => {
|
||||
if (props.publicNoBtn === false) {
|
||||
updateEdit(false);
|
||||
}
|
||||
props.deleted();
|
||||
};
|
||||
|
||||
const resetFilter = () => {
|
||||
// reset ค่าที่ค้นหาเมื่อกดปุ่ม X ในกล่องค้นหา
|
||||
emit("update:inputfilter", "");
|
||||
filterRef.value.focus();
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.icon-color {
|
||||
color: #4154b3;
|
||||
}
|
||||
.custom-header-table {
|
||||
max-height: 64vh;
|
||||
.q-table tr:nth-child(odd) td {
|
||||
background: white;
|
||||
}
|
||||
.q-table tr:nth-child(even) td {
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
.q-table thead tr {
|
||||
background: #ecebeb;
|
||||
}
|
||||
|
||||
.q-table thead tr th {
|
||||
position: sticky;
|
||||
z-index: 1;
|
||||
}
|
||||
/* this will be the loading indicator */
|
||||
.q-table thead tr:last-child th {
|
||||
/* height of all previous header rows */
|
||||
top: 48px;
|
||||
}
|
||||
.q-table thead tr:first-child th {
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
11
src/components/__tests__/HelloWorld.spec.ts
Normal file
11
src/components/__tests__/HelloWorld.spec.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { mount } from "@vue/test-utils";
|
||||
// import HelloWorld from '../HelloWorld.vue'
|
||||
|
||||
describe("HelloWorld", () => {
|
||||
it("renders properly", () => {
|
||||
// const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } })
|
||||
// expect(wrapper.text()).toContain('Hello Vitest')
|
||||
});
|
||||
});
|
||||
598
src/interface/request/main/main.ts
Normal file
598
src/interface/request/main/main.ts
Normal file
|
|
@ -0,0 +1,598 @@
|
|||
import { readonly } from "vue";
|
||||
interface ScrollType {
|
||||
position: number;
|
||||
direction: string;
|
||||
directionChanged: boolean;
|
||||
inflectionPoint: number;
|
||||
delta: number;
|
||||
}
|
||||
|
||||
interface tabType {
|
||||
key: number;
|
||||
label: string;
|
||||
tag: string;
|
||||
}
|
||||
interface childrenType {
|
||||
key: number;
|
||||
label: string;
|
||||
path?: string;
|
||||
}
|
||||
|
||||
interface menuType {
|
||||
key: number;
|
||||
icon: string;
|
||||
activeIcon: string;
|
||||
label: string;
|
||||
path: string;
|
||||
children?: childrenType[];
|
||||
}
|
||||
|
||||
interface notiType {
|
||||
id: string;
|
||||
sender: string;
|
||||
body: string;
|
||||
timereceive: Date;
|
||||
}
|
||||
|
||||
interface optionType {
|
||||
icon: string;
|
||||
label: string;
|
||||
value: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
const menuList = readonly<any[]>([
|
||||
{
|
||||
key: 1,
|
||||
icon: "mdi-home-variant-outline",
|
||||
activeIcon: "mdi-home-variant",
|
||||
label: "หน้าแรก",
|
||||
path: "dashboard",
|
||||
role: "dashboard",
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
icon: "mdi-file-outline",
|
||||
activeIcon: "document",
|
||||
label: "คู่มือการใช้งาน",
|
||||
path: "manual",
|
||||
role: "metadata",
|
||||
},
|
||||
// {
|
||||
// key: 3,
|
||||
// icon: "o_groups",
|
||||
// activeIcon: "groups",
|
||||
// label: "โครงสร้างอัตรากำลัง",
|
||||
// path: "organizational",
|
||||
// role: "organization",
|
||||
// children: [
|
||||
// {
|
||||
// key: 3.1,
|
||||
// label: "จัดการตำแหน่ง",
|
||||
// path: "organizationalMapping",
|
||||
// },
|
||||
// {
|
||||
// key: 3.2,
|
||||
// label: "แผนภูมิโครงสร้าง",
|
||||
// path: "organizationalStructChart",
|
||||
// },
|
||||
// {
|
||||
// key: 3.3,
|
||||
// label: "แผนภูมิองค์กร",
|
||||
// path: "organizationalOrgChart",
|
||||
// },
|
||||
// {
|
||||
// key: 3.4,
|
||||
// label: "ผังโครงสร้าง",
|
||||
// path: "organizationalTree",
|
||||
// },
|
||||
// {
|
||||
// key: 3.5,
|
||||
// label: "ผังโครงสร้างลูกจ้าง",
|
||||
// path: "organizationalEmployee",
|
||||
// },
|
||||
// {
|
||||
// key: 3.6,
|
||||
// label: "จัดการบัญชี 2",
|
||||
// path: "manageReport2",
|
||||
// },
|
||||
// {
|
||||
// key: 3.7,
|
||||
// label: "รายงานบัญชี",
|
||||
// path: "organizationalReport",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// key: 4,
|
||||
// icon: "o_contact_page",
|
||||
// activeIcon: "contact_page",
|
||||
// label: "ทะเบียนประวัติ",
|
||||
// path: "registry",
|
||||
// role: "registry",
|
||||
// },
|
||||
// {
|
||||
// key: 10,
|
||||
// icon: "o_contact_page",
|
||||
// activeIcon: "registry_employee_page",
|
||||
// label: "ทะเบียนประวัติลูกจ้าง",
|
||||
// path: "registry-employee",
|
||||
// role: "registryEmployee",
|
||||
// },
|
||||
// {
|
||||
// key: 10,
|
||||
// icon: "mdi-file-certificate-outline",
|
||||
// activeIcon: "order",
|
||||
// label: "ออกคำสั่ง",
|
||||
// path: "order",
|
||||
// role: "order",
|
||||
// },
|
||||
// {
|
||||
// key: 5,
|
||||
// icon: "o_search",
|
||||
// activeIcon: "search",
|
||||
// label: "สรรหา",
|
||||
// path: "recruiting",
|
||||
// role: "recruit",
|
||||
// children: [
|
||||
// {
|
||||
// label: "ตั้งค่าเว็บสรรหา",
|
||||
// path: "editorweb",
|
||||
// key: 5.1,
|
||||
// role: "recruit",
|
||||
// },
|
||||
// {
|
||||
// label: "สอบแข่งขัน",
|
||||
// path: "",
|
||||
// key: 5.2,
|
||||
// role: "recruit",
|
||||
// children: [
|
||||
// {
|
||||
// label: "จัดการรอบสอบแข่งขัน" /* แข่งขัน */,
|
||||
// path: "competePeriod",
|
||||
// role: "recruit",
|
||||
// },
|
||||
// {
|
||||
// label: "สถิติสมัครสอบแข่งขัน" /* แข่งขัน */,
|
||||
// path: "competePeriodStat",
|
||||
// role: "recruit",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// label: "คัดเลือก",
|
||||
// path: "",
|
||||
// key: 5.3,
|
||||
// role: "recruit",
|
||||
// children: [
|
||||
// {
|
||||
// label: "จัดการรอบคัดเลือก",
|
||||
// path: "qualifyPeriod",
|
||||
// role: "recruit",
|
||||
// },
|
||||
// {
|
||||
// label: "จัดการรอบคัดเลือกคนพิการ",
|
||||
// path: "disablePeriod",
|
||||
// role: "recruit",
|
||||
// },
|
||||
// {
|
||||
// label: "จัดการรายชื่อคัดเลือก",
|
||||
// path: "manage",
|
||||
// role: "recruit",
|
||||
// },
|
||||
// {
|
||||
// label: "สถิติสมัครคัดเลือก",
|
||||
// path: "qualifyPeriodStat",
|
||||
// role: "recruit",
|
||||
// },
|
||||
// {
|
||||
// label: "สถิติสมัครคัดเลือกคนพิการ",
|
||||
// path: "qualifyPeriodStatDisable",
|
||||
// role: "recruit",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// key: 6,
|
||||
// path: "placement",
|
||||
// icon: "how_to_reg",
|
||||
// activeIcon: "how_to_reg",
|
||||
// label: "บรรจุ แต่งตั้ง ย้าย โอน",
|
||||
// role: "placement",
|
||||
// children: [
|
||||
// {
|
||||
// key: 6.1,
|
||||
// label: "รายชื่อผู้สอบผ่าน" /* รายชื่อผู้สอบผ่าน */,
|
||||
// path: "placement",
|
||||
// role: "placement",
|
||||
// },
|
||||
// // {
|
||||
// // key: 6.2,
|
||||
// // label: "ออกคำสั่ง" /* ออกคำสั่งบรรจุ */,
|
||||
// // path: "Orderplacement",
|
||||
// // role: "placement",
|
||||
// // },
|
||||
// {
|
||||
// key: 6.3,
|
||||
// label: "การทดลองงาน" /* การทดลองงาน */,
|
||||
// path: "probation",
|
||||
// role: "probation",
|
||||
// },
|
||||
// {
|
||||
// key: 6.4,
|
||||
// label: "รายการขอโอน" /* */,
|
||||
// path: "transfer",
|
||||
// role: "placement",
|
||||
// },
|
||||
// {
|
||||
// key: 6.5,
|
||||
// label: "รายการรับโอน" /* */,
|
||||
// path: "receive",
|
||||
// role: "placement",
|
||||
// },
|
||||
// {
|
||||
// key: 6.6,
|
||||
// label: "รายการช่วยราชการ" /* */,
|
||||
// path: "help-government",
|
||||
// role: "placement",
|
||||
// },
|
||||
// {
|
||||
// key: 6.7,
|
||||
// label: "รายการส่งตัวกลับ" /* */,
|
||||
// path: "repatriate",
|
||||
// role: "placement",
|
||||
// },
|
||||
// {
|
||||
// key: 6.8,
|
||||
// label: "รายการแต่งตั้ง-เลื่อน" /* */,
|
||||
// path: "appoint-promote",
|
||||
// role: "placement",
|
||||
// },
|
||||
// {
|
||||
// key: 6.9,
|
||||
// label: "รายการย้าย" /* */,
|
||||
// path: "relocation",
|
||||
// role: "placement",
|
||||
// },
|
||||
// {
|
||||
// key: 6.1,
|
||||
// label: "รายการอื่นๆ" /* */,
|
||||
// path: "other",
|
||||
// role: "placement",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// key: 7,
|
||||
// icon: "mdi-account-cancel-outline",
|
||||
// activeIcon: "mdi-account-cancel",
|
||||
// label: "พ้นจากราชการ",
|
||||
// path: "retirement",
|
||||
// role: "retirement",
|
||||
// children: [
|
||||
// {
|
||||
// key: 7.1,
|
||||
// label: "ประกาศเกษียณ",
|
||||
// path: "retirement",
|
||||
// role: "retirement",
|
||||
// },
|
||||
// {
|
||||
// key: 7.2,
|
||||
// label: "รายการลาออก",
|
||||
// path: "resign",
|
||||
// role: "retirement",
|
||||
// },
|
||||
// // {
|
||||
// // key: 7.3,
|
||||
// // label: "คำสั่งลาออก",
|
||||
// // path: "resign-order",
|
||||
// // role: "retirement",
|
||||
// // },
|
||||
// {
|
||||
// key: 7.3,
|
||||
// label: "Exit interview",
|
||||
// path: "exit-Interview",
|
||||
// role: "retirement",
|
||||
// },
|
||||
// {
|
||||
// key: 7.4,
|
||||
// label: "รายการบันทึกการถึงแก่กรรม",
|
||||
// path: "deceased",
|
||||
// role: "retirement",
|
||||
// },
|
||||
// {
|
||||
// key: 7.5,
|
||||
// label: "รายการให้ออก",
|
||||
// path: "dismiss-order",
|
||||
// role: "retirement",
|
||||
// },
|
||||
// {
|
||||
// key: 7.6,
|
||||
// label: "รายการปลดออก",
|
||||
// path: "discharged",
|
||||
// role: "retirement",
|
||||
// },
|
||||
// {
|
||||
// key: 7.7,
|
||||
// label: "รายการไล่ออก",
|
||||
// path: "expulsion",
|
||||
// role: "retirement",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// key: 8,
|
||||
// icon: "mdi-medal-outline",
|
||||
// activeIcon: "mdi-medal",
|
||||
// label: "เครื่องราชฯ",
|
||||
// path: "insignia",
|
||||
// role: "insignia",
|
||||
// children: [
|
||||
// {
|
||||
// key: 8.1,
|
||||
// label: "รอบการเสนอขอ",
|
||||
// path: "insigniaProposals",
|
||||
// role: "insignia",
|
||||
// },
|
||||
// {
|
||||
// key: 8.2,
|
||||
// label: "จัดการคำขอ",
|
||||
// path: "insigniaManage",
|
||||
// role: "insignia",
|
||||
// },
|
||||
// {
|
||||
// key: 8.3,
|
||||
// label: "บันทึกผลการเสนอขอ",
|
||||
// path: "insigniaRecord",
|
||||
// role: "insignia",
|
||||
// },
|
||||
// {
|
||||
// key: 8.4,
|
||||
// label: "จัดสรรเครื่องราชฯ",
|
||||
// path: "insigniaAllocate",
|
||||
// role: "insignia",
|
||||
// },
|
||||
// {
|
||||
// key: 8.6,
|
||||
// label: "ยืม-คืนเครื่องราชฯ",
|
||||
// path: "insigniaBorrow",
|
||||
// role: "insignia",
|
||||
// },
|
||||
// {
|
||||
// key: 8.5,
|
||||
// label: "รายงาน",
|
||||
// path: "insigniaReport",
|
||||
// role: "insignia",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// key: 8,
|
||||
// icon: "mdi-medal-outline",
|
||||
// activeIcon: "mdi-medal",
|
||||
// label: "เครื่องราชฯ",
|
||||
// path: "insignia",
|
||||
// role: "insignia",
|
||||
// children: [
|
||||
// {
|
||||
// key: 8.1,
|
||||
// label: "เครื่องราชฯ",
|
||||
// path: "",
|
||||
// role: "insignia",
|
||||
// children: [
|
||||
// {
|
||||
// label: "รอบการเสนอขอ",
|
||||
// path: "insigniaProposals",
|
||||
// role: "insignia",
|
||||
// },
|
||||
// {
|
||||
// label: "จัดการคำขอ",
|
||||
// path: "insigniaManage",
|
||||
// role: "insignia",
|
||||
// },
|
||||
// {
|
||||
// label: "บันทึกผลการได้รับพระราช...",
|
||||
// path: "insigniaRecord",
|
||||
// role: "insignia",
|
||||
// },
|
||||
// {
|
||||
// label: "บันทึกผลการจ่ายใบกำกับ",
|
||||
// path: "VatInsignia",
|
||||
// role: "insignia",
|
||||
// },
|
||||
|
||||
// {
|
||||
// label: "จัดสรรเครื่องราชฯ",
|
||||
// path: "insigniaAllocate",
|
||||
// role: "insignia",
|
||||
// },
|
||||
// {
|
||||
// label: "รายงาน",
|
||||
// path: "insigniaReport",
|
||||
// role: "insignia",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// key: 8.2,
|
||||
// label: "เหรียญจักรพรรดิมาลา",
|
||||
// path: "",
|
||||
// role: "coin",
|
||||
// children: [
|
||||
// {
|
||||
// label: "รอบการเสนอขอ",
|
||||
// path: "coinProposals",
|
||||
// role: "coin",
|
||||
// },
|
||||
// {
|
||||
// label: "จัดการคำขอ",
|
||||
// path: "coinManage",
|
||||
// role: "coin",
|
||||
// },
|
||||
// {
|
||||
// label: "บันทึกผลการได้รับพระราชทานเหรียญจักรพรรดิมาลา",
|
||||
// path: "coinReceive",
|
||||
// role: "coin",
|
||||
// },
|
||||
// {
|
||||
// label: "บันทึกผลการจ่ายใบกำกับ",
|
||||
// path: "coinPayment",
|
||||
// role: "coin",
|
||||
// },
|
||||
// {
|
||||
// label:
|
||||
// "รายชื่อที่ยื่นคำร้องขอแก้ไขข้อมูลการขอพระราชทานเหรียญจักรพรรดิมาลา",
|
||||
// path: "coinRequest",
|
||||
// role: "coin",
|
||||
// },
|
||||
// // {
|
||||
// // label: "ประวัติการยื่นขอ",
|
||||
// // path: "coinHistory",
|
||||
// // role: "coin",
|
||||
// // },
|
||||
// {
|
||||
// label: "จัดสรรเหรียญตรา",
|
||||
// path: "coinAllocate",
|
||||
// role: "coin",
|
||||
// },
|
||||
// {
|
||||
// label: "รายงาน",
|
||||
// path: "coinReport",
|
||||
// role: "coin",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
]);
|
||||
|
||||
const tabList = readonly<tabType[]>([
|
||||
{
|
||||
key: 1,
|
||||
label: "ข้อมูลทั่วไป",
|
||||
tag: "information",
|
||||
},
|
||||
{
|
||||
key: 19,
|
||||
label: "ประวัติการเปลี่ยนชื่อ",
|
||||
tag: "oldName",
|
||||
},
|
||||
{
|
||||
key: 16,
|
||||
label: "ข้อมูลราชการ",
|
||||
tag: "government",
|
||||
},
|
||||
{
|
||||
key: 17,
|
||||
label: "ข้อมูลที่อยู่",
|
||||
tag: "address",
|
||||
},
|
||||
{
|
||||
key: 18,
|
||||
label: "ข้อมูลครอบครัว",
|
||||
tag: "family",
|
||||
},
|
||||
{
|
||||
key: 15,
|
||||
label: "ใบอนุญาตประกอบอาชีพ",
|
||||
tag: "certicate",
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
label: "ประวัติการศึกษา",
|
||||
tag: "education",
|
||||
},
|
||||
{
|
||||
key: 3,
|
||||
label: "การฝึกอบรม/ดูงาน",
|
||||
tag: "training",
|
||||
},
|
||||
{
|
||||
key: 4,
|
||||
label: "เครื่องราชอิสริยาภรณ์",
|
||||
tag: "insignia",
|
||||
},
|
||||
{
|
||||
key: 5,
|
||||
label: "ประกาศเกียรติคุณ",
|
||||
tag: "coined",
|
||||
},
|
||||
{
|
||||
key: 6,
|
||||
label: "ผลการประเมินปฏิบัติราชการ",
|
||||
tag: "assessment",
|
||||
},
|
||||
{
|
||||
key: 7,
|
||||
label: "ตำแหน่ง/เงินเดือน/ค่าจ้าง",
|
||||
tag: "position",
|
||||
},
|
||||
{
|
||||
key: 8,
|
||||
label: "วินัย",
|
||||
tag: "rule",
|
||||
},
|
||||
{
|
||||
key: 9,
|
||||
label: "การลา",
|
||||
tag: "leave",
|
||||
},
|
||||
{
|
||||
key: 10,
|
||||
label: "ความสามารถพิเศษ",
|
||||
tag: "talent",
|
||||
},
|
||||
{
|
||||
key: 11,
|
||||
label: "ปฎิบัติราชการพิเศษ",
|
||||
tag: "work",
|
||||
},
|
||||
{
|
||||
key: 12,
|
||||
label: "บันทึกวันที่ไม่ได้รับเงินเดือนฯ",
|
||||
tag: "record",
|
||||
},
|
||||
{
|
||||
key: 13,
|
||||
label: "อื่นๆ",
|
||||
tag: "other",
|
||||
},
|
||||
{
|
||||
key: 14,
|
||||
label: "เอกสารหลักฐาน",
|
||||
tag: "document",
|
||||
},
|
||||
]);
|
||||
|
||||
const tabListPlacement = readonly<tabType[]>([
|
||||
{
|
||||
key: 1,
|
||||
label: "ข้อมูลทั่วไป",
|
||||
tag: "information",
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
label: "ใบอนุญาตประกอบอาชีพ",
|
||||
tag: "certicate",
|
||||
},
|
||||
{
|
||||
key: 3,
|
||||
label: "ประวัติการศึกษา",
|
||||
tag: "education",
|
||||
},
|
||||
{
|
||||
key: 4,
|
||||
label: "ผลการสอบ",
|
||||
tag: "examresult",
|
||||
},
|
||||
{
|
||||
key: 5,
|
||||
label: "การคัดกรองคุณสมบัติ",
|
||||
tag: "qualification",
|
||||
},
|
||||
]);
|
||||
|
||||
export { menuList, tabList, tabListPlacement };
|
||||
export type { ScrollType, tabType, menuType, notiType, optionType };
|
||||
46
src/interface/request/manage/prefix.ts
Normal file
46
src/interface/request/manage/prefix.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
//response api เกี่ยวกับ status code กับ error
|
||||
interface RequestHistoryObject {
|
||||
message: String;
|
||||
result: ResultHistoryObject;
|
||||
status: number;
|
||||
}
|
||||
|
||||
//rusult แนบ id version mongo
|
||||
interface ResultHistoryObject {
|
||||
id: String;
|
||||
items: RequestPrefixHistoryObject;
|
||||
version: String;
|
||||
}
|
||||
|
||||
//ข้อมูล คำนำหน้าชื่อ
|
||||
interface RequestPrefixHistoryObject {
|
||||
createdAt?: Date;
|
||||
createdFullName: String;
|
||||
createdUserId: String;
|
||||
id: String;
|
||||
isActive: Boolean;
|
||||
lastUpdateFullName: String;
|
||||
lastUpdateUserId: String;
|
||||
lastUpdatedAt?: Date;
|
||||
name: String;
|
||||
}
|
||||
|
||||
//columns
|
||||
interface PrefixColumns {
|
||||
[index: number]: {
|
||||
name: String;
|
||||
align: String;
|
||||
label: String;
|
||||
sortable: Boolean;
|
||||
field: String;
|
||||
headerStyle: String;
|
||||
style: String;
|
||||
};
|
||||
}
|
||||
|
||||
export type {
|
||||
RequestHistoryObject,
|
||||
ResultHistoryObject,
|
||||
RequestPrefixHistoryObject,
|
||||
PrefixColumns,
|
||||
};
|
||||
27
src/interface/response/dashboard/dashboard.ts
Normal file
27
src/interface/response/dashboard/dashboard.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
interface ResponseInbox {
|
||||
body: string;
|
||||
createdAt: Date;
|
||||
createdFullName: string;
|
||||
createdUserId: string;
|
||||
id: string;
|
||||
isOpen: boolean;
|
||||
lastUpdateFullName: string;
|
||||
lastUpdateUserId: string;
|
||||
lastUpdatedAt: Date;
|
||||
openDate: Date | null;
|
||||
payload: string;
|
||||
receiveDate: Date;
|
||||
receiverUserId: string;
|
||||
subject: string;
|
||||
}
|
||||
|
||||
interface DataInbox {
|
||||
no: string;
|
||||
sender: string;
|
||||
subject: string;
|
||||
timereceive: Date;
|
||||
body: string;
|
||||
ratingModel: number;
|
||||
}
|
||||
|
||||
export type { ResponseInbox, DataInbox };
|
||||
14
src/interface/response/manage/prefix.ts
Normal file
14
src/interface/response/manage/prefix.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
//ข้อมูล คำนำหน้าชื่อ
|
||||
interface ResponsePrefixHistoryObject {
|
||||
createdAt?: Date;
|
||||
createdFullName: String;
|
||||
createdUserId: String;
|
||||
id: String;
|
||||
isActive: Boolean;
|
||||
lastUpdateFullName: String;
|
||||
lastUpdateUserId: String;
|
||||
lastUpdatedAt?: Date;
|
||||
name: String;
|
||||
}
|
||||
|
||||
export type { ResponsePrefixHistoryObject };
|
||||
76
src/main.ts
Normal file
76
src/main.ts
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
import { createApp, defineAsyncComponent } from "vue";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import { Dialog, Notify, Quasar, Loading } from "quasar";
|
||||
import quasarUserOptions from "./quasar-user-options";
|
||||
|
||||
import "quasar/src/css/index.sass";
|
||||
import th from "quasar/lang/th";
|
||||
|
||||
import http from "./plugins/http";
|
||||
import { createPinia } from "pinia";
|
||||
// organization
|
||||
// position
|
||||
// positionEmployee
|
||||
//calendar
|
||||
// insignia
|
||||
|
||||
// import './assets/main.css'
|
||||
|
||||
// Import GlobalFilters
|
||||
import filters from "./plugins/filters";
|
||||
|
||||
const app = createApp(App);
|
||||
const pinia = createPinia();
|
||||
|
||||
// เพิ่ม Global Filters ลงใน App
|
||||
app.config.globalProperties.$filters = filters;
|
||||
|
||||
app.use(router);
|
||||
app.use(pinia);
|
||||
|
||||
app.use(
|
||||
Quasar,
|
||||
{
|
||||
plugins: {
|
||||
Notify,
|
||||
Dialog,
|
||||
Loading,
|
||||
}, // import Quasar plugins and add here
|
||||
config: {
|
||||
notify: {
|
||||
/* look at QuasarConfOptions from the API card */
|
||||
},
|
||||
loading: {
|
||||
/* look at QuasarConfOptions from the API card */
|
||||
},
|
||||
},
|
||||
lang: th,
|
||||
}
|
||||
// quasarUserOptions // build ไม่ผ่านหลัง install code org&structure chart เลยต้องคอมเม้นไว้ก่อน เทสแล้วยังรันได้หลังคอมเม้น
|
||||
);
|
||||
|
||||
//** Global Components */
|
||||
app.component(
|
||||
"data-table",
|
||||
defineAsyncComponent(() => import("@/components/TableView.vue"))
|
||||
);
|
||||
|
||||
app.component(
|
||||
"full-loader",
|
||||
defineAsyncComponent(() => import("@/components/FullLoader.vue"))
|
||||
);
|
||||
|
||||
app.component(
|
||||
"selector",
|
||||
defineAsyncComponent(() => import("@/components/Selector.vue"))
|
||||
);
|
||||
|
||||
app.component(
|
||||
"d-table",
|
||||
defineAsyncComponent(() => import("@/components/Table.vue"))
|
||||
);
|
||||
|
||||
app.config.globalProperties.$http = http;
|
||||
|
||||
app.mount("#app");
|
||||
7
src/modules/01_manual/components/01_login.vue
Normal file
7
src/modules/01_manual/components/01_login.vue
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
<template>
|
||||
<div class="toptitle text-dark col-12 row items-center">
|
||||
คู่มือการเข้าสู่ระบบ (Login)
|
||||
<q-space />
|
||||
</div>
|
||||
</template>
|
||||
10
src/modules/01_manual/interface/index/Main.ts
Normal file
10
src/modules/01_manual/interface/index/Main.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
interface Pagination {
|
||||
rowsPerPage: number;
|
||||
}
|
||||
|
||||
interface DataOption {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export type { Pagination, DataOption };
|
||||
14
src/modules/01_manual/interface/request/Main.ts
Normal file
14
src/modules/01_manual/interface/request/Main.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
interface DataSumCalendarObject {
|
||||
id: number;
|
||||
monthFull: String;
|
||||
count: number;
|
||||
color: String;
|
||||
}
|
||||
|
||||
interface DataListsObject {
|
||||
id: number;
|
||||
count: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export type { DataSumCalendarObject, DataListsObject };
|
||||
14
src/modules/01_manual/router.ts
Normal file
14
src/modules/01_manual/router.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
const ManualHomePage = () => import("@/modules/01_manual/views/Main.vue");
|
||||
|
||||
export default [
|
||||
{
|
||||
path: "/manual",
|
||||
name: "manual",
|
||||
component: ManualHomePage,
|
||||
meta: {
|
||||
Auth: true,
|
||||
Key: [1],
|
||||
Role: "metadata",
|
||||
},
|
||||
},
|
||||
];
|
||||
0
src/modules/01_manual/store.ts
Normal file
0
src/modules/01_manual/store.ts
Normal file
10
src/modules/01_manual/views/Main.vue
Normal file
10
src/modules/01_manual/views/Main.vue
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import LoginPage from "@/modules/01_manual/components/01_login.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<LoginPage />
|
||||
|
||||
</div>
|
||||
</template>
|
||||
25
src/plugins/axios.ts
Normal file
25
src/plugins/axios.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import axios from "axios"
|
||||
import config from "process"
|
||||
// import { dotnetPath } from "../path/axiosPath";
|
||||
// import { getToken } from "@baloise/vue-keycloak";
|
||||
import keycloak from "../plugins/keycloak"
|
||||
|
||||
const axiosInstance = axios.create({
|
||||
withCredentials: false,
|
||||
})
|
||||
|
||||
// axiosInstance.defaults.baseURL = dotnetPath;
|
||||
axiosInstance.interceptors.request.use(
|
||||
async (config) => {
|
||||
const token = await keycloak.token
|
||||
config.headers = {
|
||||
Authorization: `Bearer ${token}`,
|
||||
}
|
||||
return config
|
||||
},
|
||||
(error) => {
|
||||
Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
export default axiosInstance
|
||||
22
src/plugins/filters.ts
Normal file
22
src/plugins/filters.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* GLOABL Filters
|
||||
* - ไฟล์นี้จะไว้เก็บฟังก์ชันง่าย ๆ พวก Helper Functions ทั้งหลาย
|
||||
*/
|
||||
|
||||
|
||||
const filters = {
|
||||
|
||||
/**
|
||||
* ฟังก์ชัน compactNumber ใช้แปลงตัวเลขยาว ๆ ให้กลายเป็นเลขสั้น ๆ แบบที่พวก Social Media ชอบใช้กัน เช่น 1,000 แปลงเป็น 1K หรือ 1,000,000 แปลงเป็น 1M
|
||||
* วิธีใช้ : {{ $filters.compactNumber(value) }}
|
||||
*
|
||||
* @param val รับค่าพารามิเตอร์เป็นตัวแปรชนิดตัวเลข
|
||||
* @returns คืนค่าเป็นตัวเลขที่แปลงค่าแล้ว
|
||||
*/
|
||||
compactNumber (val: number) {
|
||||
const formatter = Intl.NumberFormat('en', { notation: 'compact'})
|
||||
return formatter.format(val)
|
||||
}
|
||||
}
|
||||
|
||||
export default filters;
|
||||
45
src/plugins/http.ts
Normal file
45
src/plugins/http.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import Axios, { type AxiosRequestConfig, type AxiosResponse } from "axios";
|
||||
import keycloak from "./keycloak";
|
||||
|
||||
const http = Axios.create({
|
||||
timeout: 1000000000, // เพิ่มค่า timeout
|
||||
headers: {
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
},
|
||||
});
|
||||
|
||||
http.interceptors.request.use(
|
||||
async function (config: AxiosRequestConfig<any>) {
|
||||
await keycloak.updateToken(1);
|
||||
config.headers = config.headers ?? {};
|
||||
const token = keycloak.token;
|
||||
// const token = localStorage.getItem("access_token")
|
||||
// const token =
|
||||
// "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxU2VKV2dVRFVlNXZwNS13Q1ZHaG9lT2l4bDJTTkdKemthLU5ZN211NXZJIn0.eyJleHAiOjE2NzI0MTI1NDksImlhdCI6MTY3MjM3NjU0OSwiYXV0aF90aW1lIjoxNjcyMzc2NTQ5LCJqdGkiOiI1MTVhY2IwNC1jODQ3LTQzM2YtYjUxOC03ODUzMzJhY2ZjNWYiLCJpc3MiOiJodHRwczovL2tleWNsb2FrLmZyYXBwZXQuc3lub2xvZ3kubWUvYXV0aC9yZWFsbXMvYm1hLWVociIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJlZmM5YjRlMC1mZGU2LTQ1NDQtYmU1OS1lMTA0MjEwMjUzZjAiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJibWEtZWhyIiwibm9uY2UiOiI3NjMyMGI3ZS0xZTMxLTQ5ODYtYWIzOC1iOTUyYjFlODY3OGYiLCJzZXNzaW9uX3N0YXRlIjoiMDZlNTBkZjktNzAyNi00ZGIwLTkxMjgtMWY3Y2FiYTRkNDEyIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwczovL2xvY2FsaG9zdDo3MDA2Il0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLWJtYS1laHIiLCJvZmZsaW5lX2FjY2VzcyIsImFkbWluIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBlbWFpbCBwcm9maWxlIiwic2lkIjoiMDZlNTBkZjktNzAyNi00ZGIwLTkxMjgtMWY3Y2FiYTRkNDEyIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInJvbGUiOlsiZGVmYXVsdC1yb2xlcy1ibWEtZWhyIiwib2ZmbGluZV9hY2Nlc3MiLCJhZG1pbiIsInVtYV9hdXRob3JpemF0aW9uIl0sIm5hbWUiOiJTeXN0ZW0gQWRtaW5pc3RyYXRvciIsInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluIiwiZ2l2ZW5fbmFtZSI6IlN5c3RlbSIsImZhbWlseV9uYW1lIjoiQWRtaW5pc3RyYXRvciIsImVtYWlsIjoiYWRtaW5AbG9jYWxob3N0In0.xmfJ3pzI-jLYsaiFXyjTW7gfAEpvUmMVsp9BsB1CfRCVOKiGBbuZhnQY8W-1SWVAx1NjJ55L-zMHPK6hk1dRPLbEse3DlIBZw04W9j8m-Wz3eqdHf_UCjmrXb8qAwkeq0Iaxq9mVfJJeQWeKhFBi-Ff8ek4hCXTYDICXS8ny_BaC5WkyrefHQ2xBqQjwRyoxsg4IoVMjXYNb8L9A-4BNlRfs928SqgFYCRlF5h6zw_rC0XoLrGTmqeacBdpey-r3j2g_lTqWy8mQg2T9s65IDqW3kFPOsr0SVO88sjlFbN9Et0L57RmiqORk_RwzbWg-_Yb6dOuolXsnjBOhOoTzkA";
|
||||
if (token) config.headers.Authorization = `Bearer ${token}`;
|
||||
return config;
|
||||
},
|
||||
function (error: any) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
http.interceptors.response.use(
|
||||
function (response: AxiosResponse<any, any>) {
|
||||
return response;
|
||||
},
|
||||
function (error: any) {
|
||||
if (typeof error !== undefined) {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (error.hasOwnProperty("response")) {
|
||||
if (error.response.status === 401 || error.response.status === 403) {
|
||||
// Store.commit("SET_ERROR_MESSAGE", error.response.data.message);
|
||||
// Store.commit("REMOVE_ACCESS_TOKEN")
|
||||
}
|
||||
}
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default http;
|
||||
23
src/plugins/keycloak.ts
Normal file
23
src/plugins/keycloak.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* front connect to keycloak
|
||||
*/
|
||||
import Keycloak from "keycloak-js";
|
||||
// import config from "../app.config";
|
||||
// import http from "../shared/http";
|
||||
// import router from "../router";
|
||||
|
||||
const initOptions = {
|
||||
// url: "https://keycloak.frappet.synology.me/auth/",
|
||||
realm: "bma-ehr",
|
||||
clientId: "bma-ehr-vue3",
|
||||
url: "https://id.frappet.synology.me/",
|
||||
// realm: "bma-ehr-exam",
|
||||
// clientId: "bma-ehr-exam-vue3",
|
||||
}; //option keycloak ที่จะ connect
|
||||
|
||||
const keycloak = Keycloak(initOptions);
|
||||
|
||||
keycloak.onAuthSuccess = () => {}; //เพิ่มlogin สำเร็จจะมาทำฟังก์ชันนี้
|
||||
|
||||
await keycloak.init({ onLoad: "check-sso", checkLoginIframe: false }); //ทำการ connect keycloak
|
||||
export default keycloak;
|
||||
11
src/quasar-user-options.ts
Normal file
11
src/quasar-user-options.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// import "./styles/quasar.scss"
|
||||
import "@quasar/extras/material-icons/material-icons.css"
|
||||
import "@quasar/extras/material-icons-outlined/material-icons-outlined.css"
|
||||
import "@quasar/extras/fontawesome-v5/fontawesome-v5.css"
|
||||
import "@quasar/extras/mdi-v4/mdi-v4.css"
|
||||
|
||||
// To be used on app.use(Quasar, { ... })
|
||||
export default {
|
||||
config: {},
|
||||
plugins: {},
|
||||
}
|
||||
79
src/router/index.ts
Normal file
79
src/router/index.ts
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
import { createRouter, createWebHistory } from "vue-router";
|
||||
|
||||
const MainLayout = () => import("@/views/MainLayout.vue");
|
||||
const Dashboard = () => import("@/views/Dashboard.vue");
|
||||
const Error404NotFound = () => import("@/views/Error404NotFound.vue");
|
||||
|
||||
import ModuleManual from "@/modules/01_manual/router";
|
||||
|
||||
// TODO: ใช้หรือไม่?
|
||||
import keycloak from "@/plugins/keycloak";
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: "/",
|
||||
name: "home",
|
||||
component: MainLayout,
|
||||
children: [
|
||||
{
|
||||
path: "/",
|
||||
name: "dashboard",
|
||||
component: Dashboard,
|
||||
meta: {
|
||||
Auth: true,
|
||||
Key: [7],
|
||||
Role: "dashboard",
|
||||
},
|
||||
},
|
||||
...ModuleManual,
|
||||
],
|
||||
},
|
||||
/**
|
||||
* 404 Not Found
|
||||
* ref: https://router.vuejs.org/guide/essentials/dynamic-matching.html#catch-all-404-not-found-route
|
||||
*/
|
||||
{
|
||||
// path: "/:catchAll(.*)*", // TODO: ใช้ pathMatch แทนตามในเอกสารแนะนำ คงไว้เผื่อจำเป็น
|
||||
path: "/:pathMatch(.*)*",
|
||||
component: Error404NotFound,
|
||||
},
|
||||
],
|
||||
|
||||
scrollBehavior(to, from, savedPosition) {
|
||||
if (savedPosition) {
|
||||
return savedPosition;
|
||||
} else if (to.hash) {
|
||||
return {
|
||||
el: to.hash,
|
||||
behavior: "smooth",
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
if (to.meta.Auth) {
|
||||
if (!keycloak.authenticated) {
|
||||
keycloak.login({
|
||||
redirectUri: `${window.location.protocol}//${window.location.host}${to.path}`,
|
||||
locale: "th",
|
||||
});
|
||||
} else {
|
||||
// keycloak.updateToken(60);
|
||||
const role = keycloak.tokenParsed?.role;
|
||||
if (role.includes(to.meta.Role)) {
|
||||
next();
|
||||
} else {
|
||||
next({ path: "" });
|
||||
// next();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
// next();
|
||||
});
|
||||
|
||||
export default router;
|
||||
12
src/router/loader.ts
Normal file
12
src/router/loader.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
***** DEPRECATED - Must be delete later *****
|
||||
*/
|
||||
|
||||
/**โหลดหน้าแบบ async/await
|
||||
* @param view "ชี่อไฟล์".vue
|
||||
* @param folder "folderในsrc" [Ex. /src/"folder"] default=views เมื่อไม่ส่งค่า
|
||||
*/
|
||||
export function load(view: string, folder: string = "views") {
|
||||
// console.log(`@/${folder}/${view}.vue`);
|
||||
return async () => await import(`@/${folder}/${view}.vue`);
|
||||
}
|
||||
102
src/stores/data.ts
Normal file
102
src/stores/data.ts
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
import { ref, computed } from "vue";
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
export const useDataStore = defineStore("data", () => {
|
||||
// ref() คือการประกาศ state เหมือน vuex
|
||||
const count = ref<number>(0);
|
||||
const loader = ref<boolean>(false);
|
||||
|
||||
const expandedReport2 = ref<string[]>([]);
|
||||
const selectedReport2 = ref<string>("");
|
||||
const expandedRegister = ref<string[]>([]);
|
||||
const selectedRegister = ref<string>("");
|
||||
// computed() คือการประกาศ getters เหมือน vuex
|
||||
const doubleCount = computed(() => count.value * 2);
|
||||
// function() คือการประกาศ actions เหมือน vuex
|
||||
const increment = () => {
|
||||
count.value++;
|
||||
};
|
||||
// tabData เป็น paramert ใช้เปรียนเทียบ tab ให้ active
|
||||
const tabData = ref<string>("");
|
||||
/**
|
||||
* active tab หน้า รายละเอียดทะเบียนประวัติ
|
||||
* @param val string เป็นชื่อของ ตัวนั้นๆ
|
||||
*/
|
||||
const changeTab = (val: string) => {
|
||||
tabData.value = val;
|
||||
};
|
||||
|
||||
/**
|
||||
* active tab หน้า รายละเอียดทะเบียนประวัติ
|
||||
* @param val boolean false = close , true = open
|
||||
*/
|
||||
const loaderPage = (val: boolean) => {
|
||||
loader.value = val;
|
||||
};
|
||||
|
||||
/**
|
||||
* เปิด tree จัดการบัญชี2
|
||||
* @param val string เป็นชื่อของ ตัวนั้นๆ
|
||||
*/
|
||||
const changeTreeReport2 = (e: string[], s: string) => {
|
||||
expandedReport2.value = e;
|
||||
selectedReport2.value = s;
|
||||
};
|
||||
|
||||
/**
|
||||
* เปิด tree ทะเบียนประวัติ
|
||||
* @param val string เป็นชื่อของ ตัวนั้นๆ
|
||||
*/
|
||||
const changeTreeRegister = (e: string[], s: string) => {
|
||||
expandedRegister.value = e;
|
||||
selectedRegister.value = s;
|
||||
};
|
||||
|
||||
return {
|
||||
count,
|
||||
doubleCount,
|
||||
increment,
|
||||
tabData,
|
||||
changeTab,
|
||||
loader,
|
||||
loaderPage,
|
||||
expandedReport2,
|
||||
selectedReport2,
|
||||
changeTreeReport2,
|
||||
expandedRegister,
|
||||
selectedRegister,
|
||||
changeTreeRegister,
|
||||
};
|
||||
});
|
||||
|
||||
// การเขียนแบบ composition api
|
||||
// ตัวอย่างการใช้งาน use...Store() ตามชื่อที่ตั้ง
|
||||
|
||||
// import { useDataStore } from '@/stores/data'
|
||||
|
||||
//storeToRefs ใช้กรณีที่เราจะแปลงค่าเป็น state ใน หน้านั้น
|
||||
|
||||
// import { storeToRefs } from 'pinia'
|
||||
|
||||
// export default {
|
||||
// setup() {
|
||||
// const store = useDataStore()
|
||||
|
||||
// ***********************************
|
||||
// พยายามไม่ให้ ชื่อ เหมือนกับ props ** ตัวอย่างปกติ
|
||||
// const { count, doubleCount, increment } = store
|
||||
// ***********************************
|
||||
|
||||
// ตัวอย่าง แปลงค่า store เป็น state หรือ ref
|
||||
// const { name, doubleCount } = storeToRefs(store)
|
||||
// ถ้าเป็น function เรียกแยกอีกทีก็ได้
|
||||
// const { increment } = store
|
||||
// ***********************************
|
||||
|
||||
//return {
|
||||
// count,
|
||||
// doubleCount,
|
||||
// increment
|
||||
// }
|
||||
// },
|
||||
// }
|
||||
806
src/stores/mixin.ts
Normal file
806
src/stores/mixin.ts
Normal file
|
|
@ -0,0 +1,806 @@
|
|||
import { defineStore } from "pinia";
|
||||
import moment from "moment";
|
||||
import CustomComponent from "@/components/CustomDialog.vue";
|
||||
import { Loading, QSpinnerCube } from "quasar";
|
||||
|
||||
export const useCounterMixin = defineStore("mixin", () => {
|
||||
/**
|
||||
* ฟังก์ชันกลาง
|
||||
*/
|
||||
|
||||
const calAge = (
|
||||
srcDate: Date,
|
||||
birthCal: Date = new Date(),
|
||||
eng: boolean = false
|
||||
) => {
|
||||
const year = eng ? "years" : "ปี";
|
||||
const month = eng ? "months" : "เดือน";
|
||||
const day = eng ? "days" : "วัน";
|
||||
|
||||
if (srcDate == null) {
|
||||
return `0 ${year} 0 ${month} 0 ${day}`;
|
||||
}
|
||||
|
||||
const toDay = birthCal;
|
||||
const birth = new Date(srcDate);
|
||||
|
||||
const yearNow = toDay.getFullYear();
|
||||
const monthNow = toDay.getMonth();
|
||||
const dateNow = toDay.getDate();
|
||||
|
||||
const yearDob = birth.getFullYear();
|
||||
const monthDob = birth.getMonth();
|
||||
const dateDob = birth.getDate();
|
||||
|
||||
const lastYear = 12;
|
||||
const subtractDate: Object = moment().subtract(1, "months").endOf("month");
|
||||
|
||||
const lastMonths = new Date(subtractDate.toString()).getDate();
|
||||
|
||||
let yearAge = yearNow - yearDob;
|
||||
let monthAge = 0;
|
||||
let dateAge = 0;
|
||||
|
||||
if (monthNow >= monthDob) {
|
||||
monthAge = monthNow - monthDob;
|
||||
} else {
|
||||
yearAge--;
|
||||
monthAge = lastYear + monthNow - monthDob;
|
||||
}
|
||||
|
||||
if (dateNow >= dateDob) {
|
||||
dateAge = dateNow - dateDob;
|
||||
} else {
|
||||
monthAge--;
|
||||
dateAge = lastMonths + dateNow - dateDob;
|
||||
|
||||
if (monthAge < 0) {
|
||||
monthAge = 11;
|
||||
yearAge--;
|
||||
}
|
||||
}
|
||||
|
||||
const age = {
|
||||
years: yearAge,
|
||||
months: monthAge,
|
||||
days: dateAge,
|
||||
};
|
||||
|
||||
return `${yearAge} ${year} ${monthAge} ${month} ${dateAge} ${day}`;
|
||||
};
|
||||
|
||||
function date2Thai(
|
||||
srcDate: Date,
|
||||
isFullMonth: boolean = false,
|
||||
isTime: boolean = false
|
||||
) {
|
||||
if (srcDate == null) {
|
||||
return null;
|
||||
`
|
||||
`;
|
||||
}
|
||||
const date = new Date(srcDate);
|
||||
const isValidDate = Boolean(+date);
|
||||
if (!isValidDate) return srcDate.toString();
|
||||
if (isValidDate && date.getFullYear() < 1000) return srcDate.toString();
|
||||
const fullMonthThai = [
|
||||
"มกราคม",
|
||||
"กุมภาพันธ์",
|
||||
"มีนาคม",
|
||||
"เมษายน",
|
||||
"พฤษภาคม",
|
||||
"มิถุนายน",
|
||||
"กรกฎาคม",
|
||||
"สิงหาคม",
|
||||
"กันยายน",
|
||||
"ตุลาคม",
|
||||
"พฤศจิกายน",
|
||||
"ธันวาคม",
|
||||
];
|
||||
const abbrMonthThai = [
|
||||
"ม.ค.",
|
||||
"ก.พ.",
|
||||
"มี.ค.",
|
||||
"เม.ย.",
|
||||
"พ.ค.",
|
||||
"มิ.ย.",
|
||||
"ก.ค.",
|
||||
"ส.ค.",
|
||||
"ก.ย.",
|
||||
"ต.ค.",
|
||||
"พ.ย.",
|
||||
"ธ.ค.",
|
||||
];
|
||||
let dstYear = 0;
|
||||
if (date.getFullYear() > 2500) {
|
||||
dstYear = date.getFullYear();
|
||||
} else {
|
||||
dstYear = date.getFullYear() + 543;
|
||||
}
|
||||
let dstMonth = "";
|
||||
if (isFullMonth) {
|
||||
dstMonth = fullMonthThai[date.getMonth()];
|
||||
} else {
|
||||
dstMonth = abbrMonthThai[date.getMonth()];
|
||||
}
|
||||
let dstTime = "";
|
||||
if (isTime) {
|
||||
const H = date.getHours().toString().padStart(2, "0");
|
||||
const M = date.getMinutes().toString().padStart(2, "0");
|
||||
// const S = date.getSeconds().toString().padStart(2, "0")
|
||||
// dstTime = " " + H + ":" + M + ":" + S + " น."
|
||||
dstTime = " " + H + ":" + M + " น.";
|
||||
}
|
||||
return (
|
||||
date.getDate().toString().padStart(2, "0") +
|
||||
" " +
|
||||
dstMonth +
|
||||
" " +
|
||||
dstYear +
|
||||
dstTime
|
||||
);
|
||||
}
|
||||
|
||||
function dateMonth2Thai(srcDate: Date, isFullMonth = false, isTime = false) {
|
||||
if (!srcDate) return srcDate;
|
||||
const date = new Date(srcDate);
|
||||
const isValidDate = Boolean(+date);
|
||||
if (!isValidDate) return srcDate;
|
||||
if (isValidDate && date.getFullYear() < 1000) return srcDate;
|
||||
const fullMonthThai = [
|
||||
"มกราคม",
|
||||
"กุมภาพันธ์",
|
||||
"มีนาคม",
|
||||
"เมษายน",
|
||||
"พฤษภาคม",
|
||||
"มิถุนายน",
|
||||
"กรกฎาคม",
|
||||
"สิงหาคม",
|
||||
"กันยายน",
|
||||
"ตุลาคม",
|
||||
"พฤศจิกายน",
|
||||
"ธันวาคม",
|
||||
];
|
||||
const abbrMonthThai = [
|
||||
"ม.ค.",
|
||||
"ก.พ.",
|
||||
"มี.ค.",
|
||||
"เม.ย.",
|
||||
"พ.ค.",
|
||||
"มิ.ย.",
|
||||
"ก.ค.",
|
||||
"ส.ค.",
|
||||
"ก.ย.",
|
||||
"ต.ค.",
|
||||
"พ.ย.",
|
||||
"ธ.ค.",
|
||||
];
|
||||
let dstYear = 0;
|
||||
if (date.getFullYear() > 2500) {
|
||||
dstYear = date.getFullYear();
|
||||
} else {
|
||||
dstYear = date.getFullYear() + 543;
|
||||
}
|
||||
let dstMonth = "";
|
||||
if (isFullMonth) {
|
||||
dstMonth = fullMonthThai[date.getMonth()];
|
||||
} else {
|
||||
dstMonth = abbrMonthThai[date.getMonth()];
|
||||
}
|
||||
let dstTime = "";
|
||||
if (isTime) {
|
||||
const H = date.getHours().toString().padStart(2, "0");
|
||||
const M = date.getMinutes().toString().padStart(2, "0");
|
||||
// const S = date.getSeconds().toString().length === 1 ? "0" + date.getSeconds() : date.getSeconds()
|
||||
// dstTime = " " + H + ":" + M + ":" + S + " น."
|
||||
dstTime = " " + H + ":" + M + " น.";
|
||||
}
|
||||
return date.getDate().toString().padStart(2, "0") + " " + dstMonth;
|
||||
}
|
||||
|
||||
function monthYear2Thai(month: number, year: number, isFullMonth = false) {
|
||||
const date = new Date(`${year}-${month + 1}-1`);
|
||||
const fullMonthThai = [
|
||||
"มกราคม",
|
||||
"กุมภาพันธ์",
|
||||
"มีนาคม",
|
||||
"เมษายน",
|
||||
"พฤษภาคม",
|
||||
"มิถุนายน",
|
||||
"กรกฎาคม",
|
||||
"สิงหาคม",
|
||||
"กันยายน",
|
||||
"ตุลาคม",
|
||||
"พฤศจิกายน",
|
||||
"ธันวาคม",
|
||||
];
|
||||
const abbrMonthThai = [
|
||||
"ม.ค.",
|
||||
"ก.พ.",
|
||||
"มี.ค.",
|
||||
"เม.ย.",
|
||||
"พ.ค.",
|
||||
"มิ.ย.",
|
||||
"ก.ค.",
|
||||
"ส.ค.",
|
||||
"ก.ย.",
|
||||
"ต.ค.",
|
||||
"พ.ย.",
|
||||
"ธ.ค.",
|
||||
];
|
||||
let dstYear = 0;
|
||||
if (date.getFullYear() > 2500) {
|
||||
dstYear = date.getFullYear();
|
||||
} else {
|
||||
dstYear = date.getFullYear() + 543;
|
||||
}
|
||||
let dstMonth = "";
|
||||
if (isFullMonth) {
|
||||
dstMonth = fullMonthThai[date.getMonth()];
|
||||
} else {
|
||||
dstMonth = abbrMonthThai[date.getMonth()];
|
||||
}
|
||||
return dstMonth + " " + dstYear;
|
||||
}
|
||||
|
||||
function dateToISO(date: Date) {
|
||||
return (
|
||||
date.getFullYear() +
|
||||
"-" +
|
||||
appendLeadingZeroes(date.getMonth() + 1) +
|
||||
"-" +
|
||||
appendLeadingZeroes(date.getDate())
|
||||
);
|
||||
}
|
||||
|
||||
function appendLeadingZeroes(n: Number) {
|
||||
if (n <= 9) return "0" + n;
|
||||
return n;
|
||||
}
|
||||
|
||||
function textToPhone(n: string) {
|
||||
const p = n.substr(0, 3) + "-" + n.substr(3, 3) + "-" + n.substr(6, 4);
|
||||
return p;
|
||||
}
|
||||
|
||||
function textToFax(n: string) {
|
||||
const p = n.substr(0, 2) + "-" + n.substr(2, 3) + "-" + n.substr(5, 4);
|
||||
return p;
|
||||
}
|
||||
|
||||
const success = (q: any, val: string) => {
|
||||
// useQuasar ไม่สามารถใช้นอกไฟล์ .vue
|
||||
if (val !== "") {
|
||||
return q.notify({
|
||||
message: val,
|
||||
color: "primary",
|
||||
icon: "mdi-information",
|
||||
position: "bottom-right",
|
||||
multiLine: true,
|
||||
timeout: 1000,
|
||||
badgeColor: "positive",
|
||||
classes: "my-notif-class",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function notify(q: any, val: string) {
|
||||
if (val !== "") {
|
||||
q.notify({
|
||||
color: "teal-10",
|
||||
message: val,
|
||||
icon: "mdi-information",
|
||||
position: "bottom-right",
|
||||
multiLine: true,
|
||||
timeout: 7000,
|
||||
actions: [{ label: "ปิด", color: "white", handler: () => {} }],
|
||||
});
|
||||
}
|
||||
}
|
||||
function notifyError(q: any, val: string) {
|
||||
if (val !== "") {
|
||||
q.notify({
|
||||
color: "negative",
|
||||
message: val,
|
||||
icon: "mdi-alert-circle",
|
||||
position: "top",
|
||||
multiLine: true,
|
||||
timeout: 12000,
|
||||
actions: [{ label: "ปิด", color: "white", handler: () => {} }],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const messageError = (q: any, e: any = "") => {
|
||||
// q.dialog.hide();
|
||||
console.log("e.response", e.response);
|
||||
if (e.response !== undefined) {
|
||||
if (e.response.data.status !== undefined) {
|
||||
if (e.response.data.status == 401) {
|
||||
//invalid_token
|
||||
q.dialog({
|
||||
component: CustomComponent,
|
||||
componentProps: {
|
||||
title: `พบข้อผิดพลาด`,
|
||||
message: `ล็อกอินหมดอายุ กรุณาล็อกอินใหม่อีกครั้ง`,
|
||||
icon: "warning",
|
||||
color: "red",
|
||||
onlycancel: true,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
q.dialog({
|
||||
component: CustomComponent,
|
||||
componentProps: {
|
||||
title: `พบข้อผิดพลาด`,
|
||||
message: `${e.response.data.message}`,
|
||||
icon: "warning",
|
||||
color: "red",
|
||||
onlycancel: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (e.response.status == 401) {
|
||||
//invalid_token
|
||||
q.dialog({
|
||||
component: CustomComponent,
|
||||
componentProps: {
|
||||
title: `พบข้อผิดพลาด`,
|
||||
message: `ล็อกอินหมดอายุ กรุณาล็อกอินใหม่อีกครั้ง`,
|
||||
icon: "warning",
|
||||
color: "red",
|
||||
onlycancel: true,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
q.dialog({
|
||||
component: CustomComponent,
|
||||
componentProps: {
|
||||
title: `พบข้อผิดพลาด`,
|
||||
message: `ข้อมูลผิดพลาดทำให้เกิดการไม่ตอบสนองต่อการเรียกใช้งานดูเว็บไซต์`,
|
||||
icon: "warning",
|
||||
color: "red",
|
||||
onlycancel: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
q.dialog({
|
||||
component: CustomComponent,
|
||||
componentProps: {
|
||||
title: `พบข้อผิดพลาด`,
|
||||
message: `ข้อมูลผิดพลาดทำให้เกิดการไม่ตอบสนองต่อการเรียกใช้งานดูเว็บไซต์`,
|
||||
icon: "warning",
|
||||
color: "red",
|
||||
onlycancel: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const dialogMessage = (
|
||||
// ไม่เอาใส่ undefined
|
||||
q: any,
|
||||
title: string | undefined,
|
||||
message: string | undefined,
|
||||
icon: string | undefined,
|
||||
textOk: string | undefined,
|
||||
color: string | undefined,
|
||||
ok?: Function | undefined,
|
||||
cancel?: Function | undefined,
|
||||
onlycancel: Boolean = false
|
||||
) => {
|
||||
q.dialog({
|
||||
component: CustomComponent,
|
||||
componentProps: {
|
||||
title: title,
|
||||
message: message,
|
||||
icon: icon,
|
||||
color: color,
|
||||
textOk: textOk,
|
||||
onlycancel: onlycancel,
|
||||
},
|
||||
})
|
||||
.onOk(() => {
|
||||
if (ok != undefined) ok();
|
||||
})
|
||||
.onCancel(() => {
|
||||
if (cancel != undefined) cancel();
|
||||
});
|
||||
};
|
||||
|
||||
//*** Dialog ***//
|
||||
const dialogConfirm = (
|
||||
q: any,
|
||||
ok?: Function,
|
||||
title?: string, // ถ้ามี cancel action ใส่เป็น null
|
||||
desc?: string, // ถ้ามี cancel action ใส่เป็น null
|
||||
cancel?: Function
|
||||
) => {
|
||||
q.dialog({
|
||||
component: CustomComponent,
|
||||
componentProps: {
|
||||
title: title && title != null ? title : "ยืนยันการบันทึก",
|
||||
message:
|
||||
desc && desc != null
|
||||
? desc
|
||||
: "ต้องการยืนยันการบันทึกข้อมูลนี้ใช่หรือไม่?",
|
||||
icon: "info",
|
||||
color: "public",
|
||||
textOk: "ตกลง",
|
||||
onlycancel: false,
|
||||
},
|
||||
})
|
||||
.onOk(() => {
|
||||
if (ok) ok();
|
||||
})
|
||||
.onCancel(() => {
|
||||
if (cancel) cancel();
|
||||
});
|
||||
};
|
||||
|
||||
const dialogRemove = (
|
||||
q: any,
|
||||
ok?: Function,
|
||||
title?: string, // ถ้ามี cancel action ใส่เป็น null
|
||||
desc?: string, // ถ้ามี cancel action ใส่เป็น null
|
||||
cancel?: Function
|
||||
) => {
|
||||
q.dialog({
|
||||
component: CustomComponent,
|
||||
componentProps: {
|
||||
title: title && title != null ? title : "ยืนยันการลบข้อมูล",
|
||||
message:
|
||||
desc && desc != null
|
||||
? desc
|
||||
: "ต้องการยืนยันการลบข้อมูลนี้ใช่หรือไม่?",
|
||||
icon: "delete",
|
||||
color: "red",
|
||||
textOk: "ตกลง",
|
||||
onlycancel: false,
|
||||
},
|
||||
})
|
||||
.onOk(() => {
|
||||
if (ok) ok();
|
||||
})
|
||||
.onCancel(() => {
|
||||
if (cancel) cancel();
|
||||
});
|
||||
};
|
||||
|
||||
const dialogMessageNotify = (
|
||||
q: any,
|
||||
desc?: string, // ถ้ามี cancel action ใส่เป็น null
|
||||
cancel?: Function
|
||||
) => {
|
||||
q.dialog({
|
||||
component: CustomComponent,
|
||||
componentProps: {
|
||||
title: "ข้อความแจ้งเตือน",
|
||||
message: desc && desc != null ? desc : "กรุณากรอกข้อมูลให้ครบ",
|
||||
icon: "warning",
|
||||
color: "orange",
|
||||
textOk: "ตกลง",
|
||||
onlycancel: true,
|
||||
},
|
||||
}).onCancel(() => {
|
||||
if (cancel) cancel();
|
||||
});
|
||||
};
|
||||
//*** END Dialog ***//
|
||||
|
||||
const showLoader = () => {
|
||||
Loading.show({
|
||||
spinner: QSpinnerCube,
|
||||
spinnerSize: 140,
|
||||
spinnerColor: "primary",
|
||||
backgroundColor: "white",
|
||||
});
|
||||
};
|
||||
|
||||
const hideLoader = () => {
|
||||
Loading.hide();
|
||||
};
|
||||
|
||||
function modalDelete(
|
||||
q: any,
|
||||
title: string,
|
||||
message: string,
|
||||
ok: Function,
|
||||
cancel?: Function
|
||||
) {
|
||||
q.dialog({
|
||||
title: `<span class="text-red">${title}</span>`,
|
||||
message: `<span class="text-black">${message}</span>`,
|
||||
cancel: {
|
||||
flat: true,
|
||||
color: "grey-14",
|
||||
},
|
||||
ok: {
|
||||
color: "red-6",
|
||||
},
|
||||
focus: "none",
|
||||
persistent: true,
|
||||
html: true,
|
||||
})
|
||||
.onOk(() => {
|
||||
ok();
|
||||
})
|
||||
.onCancel(() => {
|
||||
if (cancel != undefined) cancel();
|
||||
})
|
||||
.onDismiss(() => {});
|
||||
}
|
||||
|
||||
function modalConfirm(
|
||||
q: any,
|
||||
title: string,
|
||||
message: string,
|
||||
ok: Function,
|
||||
cancel?: Function
|
||||
) {
|
||||
q.dialog({
|
||||
title: `<span class="text-primary">${title}</span>`,
|
||||
message: `<span class="text-black">${message}</span>`,
|
||||
cancel: {
|
||||
flat: true,
|
||||
color: "grey",
|
||||
},
|
||||
ok: {
|
||||
color: "primary",
|
||||
},
|
||||
focus: "none",
|
||||
persistent: true,
|
||||
html: true,
|
||||
})
|
||||
.onOk(() => {
|
||||
ok();
|
||||
})
|
||||
.onCancel(() => {
|
||||
if (cancel != undefined) cancel();
|
||||
})
|
||||
.onDismiss(() => {});
|
||||
}
|
||||
|
||||
function modalWarning(q: any, title: string, message: string, ok?: Function) {
|
||||
// q.dialog({
|
||||
// title: `<span class="text-red">${title}</span>`,
|
||||
// message: `<span class="text-black">${message}</span>`,
|
||||
// ok: {
|
||||
// push: true,
|
||||
// color: "primary",
|
||||
// },
|
||||
// focus: "none",
|
||||
// persistent: true,
|
||||
// html: true,
|
||||
// })
|
||||
// .onOk(() => {
|
||||
// if (ok != undefined) ok();
|
||||
// })
|
||||
// .onCancel(() => {})
|
||||
// .onDismiss(() => {});
|
||||
|
||||
q.dialog({
|
||||
component: CustomComponent,
|
||||
componentProps: {
|
||||
title: title,
|
||||
message: message,
|
||||
icon: "warning",
|
||||
color: "warning",
|
||||
onlycancel: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function modalError(q: any, title: string, message: string, ok?: Function) {
|
||||
// q.dialog({
|
||||
// title: `<span class="text-red">${title}</span>`,
|
||||
// message: `<span class="text-black">${message}</span>`,
|
||||
// ok: {
|
||||
// push: true,
|
||||
// color: "primary",
|
||||
// },
|
||||
// focus: "none",
|
||||
// persistent: true,
|
||||
// html: true,
|
||||
// })
|
||||
// .onOk(() => {
|
||||
// if (ok != undefined) ok();
|
||||
// })
|
||||
// .onCancel(() => {})
|
||||
// .onDismiss(() => {});
|
||||
|
||||
q.dialog({
|
||||
component: CustomComponent,
|
||||
componentProps: {
|
||||
title: title,
|
||||
message: message,
|
||||
icon: "warning",
|
||||
color: "red",
|
||||
onlycancel: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const dateText = (val: Date) => {
|
||||
if (val != null) {
|
||||
return date2Thai(val);
|
||||
} else {
|
||||
return "-";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* แปลงช่วงวันที่ถ้า2ค่าเป็นวันเดียวกันจะโชววันเดียวแต่ถ้าไม่เท่ากันจะแสดงเป็นช่วง
|
||||
* @param val ช่วงวันที่
|
||||
*/
|
||||
const dateThaiRange = (val: [Date, Date]) => {
|
||||
if (val === null) {
|
||||
return "";
|
||||
} else if (date2Thai(val[0]) === date2Thai(val[1])) {
|
||||
return `${date2Thai(val[0])}`;
|
||||
} else {
|
||||
return `${date2Thai(val[0])} - ${date2Thai(val[1])}`;
|
||||
}
|
||||
};
|
||||
|
||||
const weekThai = (val: Number) => {
|
||||
switch (val) {
|
||||
case 0:
|
||||
return "วันอาทิตย์";
|
||||
case 1:
|
||||
return "วันจันทร์";
|
||||
case 2:
|
||||
return "วันอังคาร";
|
||||
case 3:
|
||||
return "วันพุธ";
|
||||
case 4:
|
||||
return "วันพฤหัสบดี";
|
||||
case 5:
|
||||
return "วันศุกร์";
|
||||
case 6:
|
||||
return "วันเสาร์";
|
||||
default:
|
||||
return "-";
|
||||
}
|
||||
};
|
||||
|
||||
const genColor15 = (val: number) => {
|
||||
val = val % 15;
|
||||
switch (val) {
|
||||
case 1:
|
||||
return "pink";
|
||||
case 2:
|
||||
return "purple";
|
||||
case 3:
|
||||
return "deep-purple";
|
||||
case 4:
|
||||
return "indigo";
|
||||
case 5:
|
||||
return "blue";
|
||||
case 6:
|
||||
return "light-blue";
|
||||
case 7:
|
||||
return "cyan";
|
||||
case 8:
|
||||
return "teal";
|
||||
case 9:
|
||||
return "green";
|
||||
case 10:
|
||||
return "light-green";
|
||||
case 11:
|
||||
return "amber";
|
||||
case 12:
|
||||
return "orange";
|
||||
case 13:
|
||||
return "deep-orange";
|
||||
case 14:
|
||||
return "brown";
|
||||
case 0:
|
||||
return "blue-grey";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
const typeCategoryExam = (val: string) => {
|
||||
switch (val) {
|
||||
case "hygiene":
|
||||
return "สำนักอนามัย";
|
||||
case "physician":
|
||||
return "สำนักการแพทย์";
|
||||
case "city":
|
||||
return "สำนักผังเมือง";
|
||||
case "culture":
|
||||
return "สำนักวัฒนธรรม กีฬา และการท่องเที่ยว";
|
||||
default:
|
||||
return "-";
|
||||
}
|
||||
};
|
||||
|
||||
const typeRetire = (val: string) => {
|
||||
switch (val) {
|
||||
case "retire":
|
||||
return "เกษียณอายุราชการ";
|
||||
case "resign":
|
||||
return "ลาออก";
|
||||
case "transfer":
|
||||
return "ให้โอน";
|
||||
case "death":
|
||||
return "ถึงแก่กรรม";
|
||||
case "layoff":
|
||||
return "ให้ออก";
|
||||
case "discharge":
|
||||
return "ปลดออก";
|
||||
case "dismiss":
|
||||
return "ไล่ออก";
|
||||
case "other":
|
||||
return "อื่นๆ";
|
||||
default:
|
||||
return "-";
|
||||
}
|
||||
};
|
||||
|
||||
const typeChangeName = (val: string) => {
|
||||
switch (val) {
|
||||
case "firstName":
|
||||
return "เปลี่ยนชื่อ";
|
||||
case "lastName":
|
||||
return "เปลี่ยนนามสกุล";
|
||||
case "all":
|
||||
return "เปลี่ยนชื่อ-นามสกุล";
|
||||
default:
|
||||
return "-";
|
||||
}
|
||||
};
|
||||
|
||||
const statusLeave = (val: string) => {
|
||||
switch (val) {
|
||||
case "waitting":
|
||||
return "รออนุมัติ";
|
||||
case "reject":
|
||||
return "ไม่ผ่านการอนุมัติ";
|
||||
case "approve":
|
||||
return "ผ่านการอนุมัติ";
|
||||
case "cancel":
|
||||
return "ยกเลิก";
|
||||
default:
|
||||
return "-";
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
calAge,
|
||||
date2Thai,
|
||||
dateToISO,
|
||||
notify,
|
||||
notifyError,
|
||||
dateText,
|
||||
monthYear2Thai,
|
||||
dateMonth2Thai,
|
||||
success,
|
||||
weekThai,
|
||||
genColor15,
|
||||
typeCategoryExam,
|
||||
textToPhone,
|
||||
textToFax,
|
||||
dateThaiRange,
|
||||
modalDelete,
|
||||
modalConfirm,
|
||||
modalError,
|
||||
dialogMessage,
|
||||
messageError,
|
||||
showLoader,
|
||||
hideLoader,
|
||||
typeRetire,
|
||||
typeChangeName,
|
||||
statusLeave,
|
||||
modalWarning,
|
||||
// common dialog
|
||||
dialogConfirm,
|
||||
dialogRemove,
|
||||
dialogMessageNotify,
|
||||
};
|
||||
});
|
||||
139
src/style/quasar-variables.sass
Normal file
139
src/style/quasar-variables.sass
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
// FILE (create it): src/quasar-variables.sass
|
||||
|
||||
$primary: #02A998
|
||||
$secondary: #016987
|
||||
$accent: #9C27B0
|
||||
|
||||
// $dark: #1D1D1D
|
||||
$dark: #35473C
|
||||
|
||||
$positive: #21BA45
|
||||
$negative: #C10015
|
||||
$info: #31CCEC
|
||||
$warning: #F2C037
|
||||
|
||||
$add: #00aa86
|
||||
.text-add
|
||||
color: $add !important
|
||||
.bg-add
|
||||
background: $add !important
|
||||
|
||||
$edit: #019fc4
|
||||
.text-edit
|
||||
color: $edit !important
|
||||
.bg-edit
|
||||
background: $edit !important
|
||||
|
||||
$public: #016987
|
||||
.text-public
|
||||
color: $public !important
|
||||
.bg-public
|
||||
background: $public !important
|
||||
|
||||
$save: #4154b3
|
||||
.text-save
|
||||
color: $save !important
|
||||
.bg-save
|
||||
background: $save !important
|
||||
|
||||
$nativetab: #c8d3db
|
||||
.text-nativetab
|
||||
color: $nativetab !important
|
||||
.bg-nativetab
|
||||
background: $nativetab !important
|
||||
|
||||
$activetab: #4a5568
|
||||
.text-activetab
|
||||
color: $activetab !important
|
||||
.bg-activetab
|
||||
background: $activetab !important
|
||||
|
||||
.inputgreen .q-field__prefix,
|
||||
.inputgreen .q-field__suffix,
|
||||
.inputgreen .q-field__input,
|
||||
.inputgreen .q-field__native
|
||||
|
||||
color: rgb(6, 136, 77)
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+Thai:wght@100;200;300;400;500;600;700;800;900&display=swap')
|
||||
|
||||
$noto-thai: 'Noto Sans Thai', sans-serif
|
||||
|
||||
#azay-app,
|
||||
div
|
||||
font-family: $noto-thai !important
|
||||
text-rendering: optimizeLegibility
|
||||
-webkit-font-smoothing: antialiased
|
||||
-moz-osx-font-smoothing: grayscale
|
||||
|
||||
$separator-color: #EDEDED !default
|
||||
|
||||
.bg-teal-1
|
||||
background: #e0f2f1a6 !important
|
||||
|
||||
.table_ellipsis
|
||||
max-width: 200px
|
||||
white-space: nowrap
|
||||
overflow: hidden
|
||||
text-overflow: ellipsis
|
||||
|
||||
.table_ellipsis:hover
|
||||
word-wrap: break-word
|
||||
overflow: visible
|
||||
white-space: normal
|
||||
|
||||
.table_ellipsis2
|
||||
max-width: 25vw
|
||||
white-space: nowrap
|
||||
overflow: hidden
|
||||
text-overflow: ellipsis
|
||||
|
||||
.table_ellipsis2:hover
|
||||
word-wrap: break-word
|
||||
overflow: visible
|
||||
white-space: normal
|
||||
transition: width 2s
|
||||
|
||||
$muti-tab: #87d4cc
|
||||
.text-muti-tab
|
||||
color: $muti-tab !important
|
||||
.bg-muti-tab
|
||||
background: $muti-tab !important
|
||||
|
||||
|
||||
/* editor */
|
||||
|
||||
.q-editor
|
||||
font-size: 1rem
|
||||
line-height: 1.5rem
|
||||
font-weight: 400
|
||||
|
||||
.q-editor h1, .q-menu h1
|
||||
font-size: 1.5rem
|
||||
line-height: 2rem
|
||||
font-weight: 400
|
||||
margin-block-start: 0em
|
||||
margin-block-end: 0em
|
||||
|
||||
.q-editor h2, .q-menu h2
|
||||
font-size: 1.25rem
|
||||
line-height: 1.5rem
|
||||
font-weight: 400
|
||||
margin-block-start: 0em
|
||||
margin-block-end: 0em
|
||||
|
||||
|
||||
.q-editor h3, .q-menu h3
|
||||
font-size: 1.1rem
|
||||
line-height: 1.5rem
|
||||
font-weight: 400
|
||||
margin-block-start: 0em
|
||||
margin-block-end: 0em
|
||||
|
||||
.q-editor p, .q-menu p
|
||||
margin: 0
|
||||
|
||||
/* q-tree */
|
||||
|
||||
.q-tree
|
||||
color: #c8d3db
|
||||
8
src/views/Dashboard.vue
Normal file
8
src/views/Dashboard.vue
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
</script>
|
||||
|
||||
<!-- page:หน้าแรก -->
|
||||
<template>
|
||||
<div class="toptitle text-dark">คู่มือการใช้งานระบบ</div>
|
||||
|
||||
</template>
|
||||
27
src/views/Error404NotFound.vue
Normal file
27
src/views/Error404NotFound.vue
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "Error404NotFound",
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="fullscreen bg-blue-10 text-white text-center q-pa-md flex flex-center"
|
||||
>
|
||||
<div>
|
||||
<div class="text-h1">ไม่พบหน้าที่ต้องการ</div>
|
||||
<div class="text-h2">(404 Page Not Found)</div>
|
||||
<q-btn
|
||||
class="q-mt-xl"
|
||||
color="white"
|
||||
text-color="blue"
|
||||
unelevated
|
||||
to="/"
|
||||
label="กลับไปหน้าหลัก"
|
||||
no-caps
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
999
src/views/MainLayout.vue
Normal file
999
src/views/MainLayout.vue
Normal file
|
|
@ -0,0 +1,999 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted } from "vue";
|
||||
import keycloak from "@/plugins/keycloak";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { useDataStore } from "@/stores/data";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { scroll, useQuasar } from "quasar";
|
||||
import { useCounterMixin } from "@/stores/mixin";
|
||||
|
||||
import http from "@/plugins/http";
|
||||
import config from "@/app.config";
|
||||
|
||||
import type {
|
||||
ScrollType,
|
||||
notiType,
|
||||
optionType,
|
||||
} from "../interface/request/main/main";
|
||||
import {
|
||||
menuList,
|
||||
tabList,
|
||||
tabListPlacement,
|
||||
} from "../interface/request/main/main";
|
||||
|
||||
const { setVerticalScrollPosition, getVerticalScrollPosition } = scroll;
|
||||
const store = useDataStore();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const link = ref<string>("");
|
||||
const mixin = useCounterMixin(); //เรียกฟังก์ชันกลาง
|
||||
const {
|
||||
showLoader,
|
||||
hideLoader,
|
||||
dialogMessage,
|
||||
success,
|
||||
messageError,
|
||||
date2Thai,
|
||||
} = mixin;
|
||||
|
||||
const $q = useQuasar();
|
||||
const { tabData, loader } = storeToRefs(store);
|
||||
const { changeTab } = store;
|
||||
const miniState = ref<boolean>(false);
|
||||
const drawerR = ref<boolean>(false);
|
||||
const rightActive = ref<boolean>(false);
|
||||
const resize = ref<number>(0);
|
||||
const active = ref<number>(0);
|
||||
const drawerL = ref<boolean>(false);
|
||||
const fullname = ref<string>("");
|
||||
const role = ref<string[]>([]);
|
||||
const notiTrigger = ref<boolean>(false);
|
||||
const text = ref<string>("");
|
||||
|
||||
const notiList = ref<notiType[]>([
|
||||
{
|
||||
id: "1",
|
||||
sender: "ท",
|
||||
body: "ขอแก้ไขข้อมูลทะเบียนประวัติ",
|
||||
timereceive: new Date(),
|
||||
},
|
||||
]);
|
||||
const options = ref<optionType[]>([
|
||||
{
|
||||
icon: "mdi-account-cog",
|
||||
label: "ผู้ดูแลระบบ",
|
||||
value: "op1",
|
||||
color: "primary",
|
||||
},
|
||||
{
|
||||
icon: "mdi-account-group",
|
||||
label: "เจ้าหน้าที่",
|
||||
value: "op2",
|
||||
color: "blue",
|
||||
},
|
||||
{
|
||||
icon: "mdi-account-circle",
|
||||
label: "บุคคล",
|
||||
value: "op3",
|
||||
color: "indigo",
|
||||
},
|
||||
]);
|
||||
|
||||
/**
|
||||
* ให้แสดง แทปด้านขวา เมื่อเข้าหน้า รายละเอียดทะเบียนประวัติ
|
||||
*/
|
||||
const tabScroll = () => {
|
||||
return route.name == "registryDetail";
|
||||
};
|
||||
|
||||
/**
|
||||
* toggleBtnRight ปุ่มย่อ ขยาย drawer ขวา
|
||||
*/
|
||||
const toggleBtnRight = () => {
|
||||
drawerR.value = !drawerR.value;
|
||||
};
|
||||
|
||||
/**
|
||||
* toggleBtnLeft ปุ่มย่อ ขยาย drawer ซ้าย เมื่อหน้าจอ ย่อถึงขนาด 1024 px
|
||||
* ปกติเป็นการย่อโดยใช้ Ministate
|
||||
*/
|
||||
const toggleBtnLeft = () => {
|
||||
if (window.innerWidth < 1024) {
|
||||
drawerL.value = !drawerL.value;
|
||||
} else {
|
||||
miniState.value = !miniState.value;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Event onScroll นำ ตำแหน่ง top ที่ scroll
|
||||
* ใช้ function updateScroll
|
||||
*/
|
||||
const onScroll = (scroll: ScrollType) => {
|
||||
const { position } = scroll;
|
||||
if (route.name == "PlacementPersonalDetail") {
|
||||
updateScrollPlacement(position);
|
||||
} else {
|
||||
updateScroll(position);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* updateScroll เป็น function active แทปด้านขวา
|
||||
*/
|
||||
const updateScroll = (position: number) => {
|
||||
// เมื่อ position เป็น undifind ให้ position เป็น ตำแหน่ง top ที่ scroll
|
||||
if (position === void 0) {
|
||||
position = document.documentElement.scrollTop || document.body.scrollTop;
|
||||
}
|
||||
|
||||
let last;
|
||||
/**
|
||||
* วนหา id ของ div นั้น
|
||||
*/
|
||||
for (const i in tabList) {
|
||||
const section = tabList[i];
|
||||
const item = document.getElementById(section.tag);
|
||||
/**
|
||||
* วนหา id ของ div หน้านั้น
|
||||
* เมื่อหาไม่เจอให้ไปต่อตัวต่อไป
|
||||
* เมื่อเจอแล้ว ให้ ตำแหน่งบนสุดของ div นั้น มากกว่าหรือเท่ากับ ตำแหน่ง top ที่ scroll บวกกับ แทปด้านบน 155
|
||||
* ถ้า last เป็น undifind ให้ last เท่ากับ tag แล้ว หยุดลูป
|
||||
* ถ้าไม่ใช้ undifind ให้ last เท่ากับ tag แล้ว ลูปหาต่อ กรณี div นั้นยาว
|
||||
*/
|
||||
if (item === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.offsetTop >= position + 155) {
|
||||
if (last === void 0) {
|
||||
last = section.tag;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
last = section.tag;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* ถ้า last ไม่เท่ากับ undifind
|
||||
* ใช้ เซ็ท active ให้เป็นแทปสีฟ้า
|
||||
* และใช้ scrollIntoView ย้ายตำแหน่ง activeโดยการเลื่อนไปหา
|
||||
*/
|
||||
if (last !== void 0) {
|
||||
changeTab(last);
|
||||
const tocEl = document.getElementById("tab--" + last);
|
||||
if (tocEl) {
|
||||
tocEl.scrollIntoView({ block: "nearest" });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ให้แสดง แทปด้านขวา เมื่อเข้าหน้า รายละเอียดทะเบียนประวัติ และ rightActive เท่ากับ true
|
||||
*/
|
||||
const activeBtn = () => {
|
||||
return route.name == "registryDetail" && rightActive.value;
|
||||
};
|
||||
|
||||
/**
|
||||
* เมื่อเริ่มต้นโปรแกรมให้ฟัง event resize และ function myEventHandler
|
||||
* set function myEventHandler เพราะ state ยังไม่เซ็ท , state เซ็ทเมื่อ หน้าจอเริ่ม ขยับหน้าจอ
|
||||
* เริ่มเข้ามา state rightActive เป็น state ที่โชว์ ปุ่มขวา
|
||||
* ยังจับ boolean ผิด จึงต้อง set
|
||||
*/
|
||||
onMounted(async () => {
|
||||
myEventHandler(null, false);
|
||||
window.addEventListener("resize", (e: any) => {
|
||||
myEventHandler(e, true);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* เมื่อออกจากโปรแกรม ให้ ยกเลิกการฟัง event resize
|
||||
*/
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("resize", (e: any) => {
|
||||
myEventHandler(e, true);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* @param e event ของ resize
|
||||
* @param setSCroll เช็คว่ามาจาก event หรือป่าว
|
||||
* set state resize = ความกว้างหน้าเว็ป
|
||||
* เมื่อความกว้าง น้อยกว่า 1024( เท่ากับ น้อยกว่า 1023) ให้ rightActive เป็น true แต่ถ้า rightActive true อยู่แล้วไม่ต้อง set
|
||||
* เมื่อความกว้าง มากกว่าหรือเท่ากับ 1024 และเมื่อ rightActive เป็น true
|
||||
* และ drawerR เป็น true ให้ rightActive เป็น true ถ้า drawerR เป็น false ให้ rightActive เป็น false
|
||||
* rightActive = true ; แสดงปุ่ม drawer ด้าน ขวา
|
||||
* rightActive = false; ไม่แสดงปุ่ม drawer ด้าน ขวา
|
||||
*/
|
||||
const myEventHandler = (e: any, setSCroll: boolean) => {
|
||||
if (setSCroll) {
|
||||
resize.value = e.target.innerWidth;
|
||||
} else {
|
||||
resize.value = window.innerWidth;
|
||||
}
|
||||
if (resize.value < 1024) {
|
||||
if (!rightActive.value) {
|
||||
rightActive.value = true;
|
||||
}
|
||||
} else {
|
||||
if (rightActive.value) {
|
||||
if (drawerR.value) {
|
||||
rightActive.value = true;
|
||||
} else {
|
||||
rightActive.value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ตรวจสอบ path นั้นๆ ว่ายังอยู่ที่ path นั้น แม้จะเป็น path ที่มี child แท็ปก็ยังจะ active อยู่เช่น
|
||||
* ปกติ path จะ active เมื่อ path นั้นมีค่า ตรงตัวมันเช่น /main
|
||||
* แต่จะไม่ active เมื่อ path นั้น มี child path /main/อื่นๆ
|
||||
* @param path string
|
||||
*/
|
||||
const activeMenu = (path: string) => {
|
||||
if (path == "dashboard" && route.fullPath == "/") return true;
|
||||
if (path == "registry" && route.fullPath == "/registry-employee") return false;
|
||||
if (path == "registry" && route.fullPath.includes(`/registry-employee/edit`)) return false;
|
||||
|
||||
if (path == "registry" && route.fullPath == "/") return false;
|
||||
// if (path != "registry" && path == "registryEmployee" && route.fullPath == "/registryEmployee") return true;
|
||||
const bool = route.fullPath.includes(`/${path}`);
|
||||
|
||||
return bool;
|
||||
};
|
||||
/**
|
||||
* เป็นฟังก์ชันที่รันตลอด เพื่อให้ active ตรงตามเงื่อนไขให้เป็น true
|
||||
* @param tag string เป็นชื่อของ ตัวนั้นๆ
|
||||
*/
|
||||
const activeTab = (tag: string) => {
|
||||
return tabData.value == tag;
|
||||
};
|
||||
|
||||
/**
|
||||
* คลิกเพื่อให้ router หรือ scroll ไปยังตำแหน่งนั้นๆ
|
||||
* @param tag string เป็นชื่อของ ตัวนั้นๆ
|
||||
*/
|
||||
const tagClick = (tag: string) => {
|
||||
const hash = `#${tag}`;
|
||||
const items = document.getElementById(tag);
|
||||
const offset = Math.max(0, items == null ? 0 : items.offsetTop - 84);
|
||||
// router.replace({ hash });
|
||||
if (route.hash !== hash) {
|
||||
const check = activeBtn();
|
||||
if (check) {
|
||||
// router.replace({ hash, position: { x: 0, y: 0 } });
|
||||
// router.replace({ hash }).then(() => {
|
||||
// setVerticalScrollPosition(window, offset, 300);
|
||||
// });
|
||||
drawerR.value = !drawerR.value;
|
||||
setVerticalScrollPosition(window, offset, 300);
|
||||
} else {
|
||||
setVerticalScrollPosition(window, offset, 300);
|
||||
}
|
||||
} else {
|
||||
setVerticalScrollPosition(window, offset, 300);
|
||||
}
|
||||
};
|
||||
|
||||
//**** Tab Right หน้าจอแก้ไขข้อมูลส่วนตัวของผู้สอบผ่าน ****\\
|
||||
const tabScrollPlacement = () => {
|
||||
return route.name == "PlacementPersonalDetail";
|
||||
};
|
||||
|
||||
const updateScrollPlacement = (position: number) => {
|
||||
if (position === void 0) {
|
||||
position = document.documentElement.scrollTop || document.body.scrollTop;
|
||||
}
|
||||
|
||||
let last;
|
||||
for (const i in tabListPlacement) {
|
||||
const section = tabListPlacement[i];
|
||||
const item = document.getElementById(section.tag);
|
||||
|
||||
if (item === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.offsetTop >= position + 100) {
|
||||
if (last === void 0) {
|
||||
last = section.tag;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
last = section.tag;
|
||||
}
|
||||
}
|
||||
|
||||
if (last !== void 0) {
|
||||
changeTab(last);
|
||||
const tocEl = document.getElementById("tab--" + last);
|
||||
if (tocEl) {
|
||||
tocEl.scrollIntoView({ block: "nearest" });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const activeBtnPlacement = () => {
|
||||
return route.name == "PlacementPersonalDetail" && rightActive.value;
|
||||
};
|
||||
|
||||
const activeTabPlacement = (tag: string) => {
|
||||
return tabData.value == tag;
|
||||
};
|
||||
|
||||
const tagClickPlacement = (tag: string) => {
|
||||
const hash = `#${tag}`;
|
||||
const items = document.getElementById(tag);
|
||||
const offset = Math.max(0, items == null ? 0 : items.offsetTop + 50);
|
||||
// router.replace({ hash });
|
||||
if (route.hash !== hash) {
|
||||
const checkPlacement = activeBtnPlacement();
|
||||
if (checkPlacement) {
|
||||
drawerR.value = !drawerR.value;
|
||||
setVerticalScrollPosition(window, offset, 300);
|
||||
} else {
|
||||
setVerticalScrollPosition(window, offset, 300);
|
||||
}
|
||||
} else {
|
||||
setVerticalScrollPosition(window, offset, 300);
|
||||
}
|
||||
};
|
||||
//**** End Tab Right หน้าจอแก้ไขข้อมูลส่วนตัวของผู้สอบผ่าน ****\\
|
||||
|
||||
/**
|
||||
* logout keycloak
|
||||
* confirm ก่อนออกจากระบบ
|
||||
*/
|
||||
const doLogout = () => {
|
||||
$q.dialog({
|
||||
title: "ยืนยันการออกจากระบบ",
|
||||
message: `ต้องการออกจากระบบใช้หรือไม่?`,
|
||||
cancel: "ยกเลิก",
|
||||
ok: "ยืนยัน",
|
||||
persistent: true,
|
||||
}).onOk(() => {
|
||||
keycloak.logout();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* ดิงชื่อผู้ใช้งานจาก keycloak
|
||||
*/
|
||||
if (keycloak.tokenParsed != null) {
|
||||
fullname.value = keycloak.tokenParsed.name;
|
||||
role.value = keycloak.tokenParsed.role;
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- โครงเว็บ -->
|
||||
<template>
|
||||
<!-- แบบเก่า design แรก -->
|
||||
<!-- <q-layout view="lHh Lpr lff"> -->
|
||||
<!-- ปรับให้กับหน้า รายละเอียดทะเบียนประวัติ -->
|
||||
<q-layout view="lHh LpR lff" @scroll="onScroll">
|
||||
<!-- header -->
|
||||
<q-header flat class="bg-grey-2 text-dark" height-hint="7">
|
||||
<q-toolbar style="padding: 0 2%">
|
||||
<q-btn
|
||||
size="13px"
|
||||
class="bg-grey-3"
|
||||
flat
|
||||
dense
|
||||
round
|
||||
@click="toggleBtnLeft"
|
||||
aria-label="Menu"
|
||||
>
|
||||
<q-icon
|
||||
:name="miniState == false ? 'mdi-backburger' : 'mdi-menu-open'"
|
||||
size="20px"
|
||||
color="grey-7"
|
||||
/>
|
||||
</q-btn>
|
||||
|
||||
<q-space />
|
||||
|
||||
<!-- Search -->
|
||||
<!-- <q-input dense rounded standout v-model="text" placeholder="ค้นหา">
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="mdi-magnify" size="20px" color="grey-7" />
|
||||
</template>
|
||||
</q-input> -->
|
||||
<!-- <q-btn class="bg-grey-3" flat dense round>
|
||||
<q-icon name="mdi-magnify" size="20px" color="grey-7" />
|
||||
</q-btn>
|
||||
-->
|
||||
<!-- Notification -->
|
||||
<div class="row items-center no-wrap">
|
||||
<q-btn-dropdown size="md" dropdown-color="grey" flat>
|
||||
<template v-slot:label>
|
||||
<q-item v-close-popup class="q-pa-none">
|
||||
<q-item-section :avatar="$q.screen.gt.xs">
|
||||
<q-avatar color="grey-3">
|
||||
<!-- <img src="https://cdn.quasar.dev/img/avatar.png" /> -->
|
||||
<q-icon name="mdi-account" size="22px" color="grey-7" />
|
||||
</q-avatar>
|
||||
</q-item-section>
|
||||
<q-item-section class="text-left gt-xs">
|
||||
<q-item-label class="text-caption text-weight-medium">{{
|
||||
fullname
|
||||
}}</q-item-label>
|
||||
<!-- <q-item-label caption>เจ้าหน้าที่ ก.ก.</q-item-label> -->
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
<div
|
||||
class="row justify-center"
|
||||
style="border-top: solid 3px #1bb19b !important; width: 273.797px"
|
||||
>
|
||||
<div class="column items-center col-12 q-py-md" color="grey-3">
|
||||
<q-avatar size="72px" color="grey-4">
|
||||
<q-icon name="mdi-account" color="grey-7" />
|
||||
<!-- <img :src="require('@/assets/logo.png')" /> -->
|
||||
</q-avatar>
|
||||
<div class="text-subtitle2 q-mt-md q-mb-xs text-center">
|
||||
{{ fullname }}
|
||||
</div>
|
||||
<q-btn
|
||||
color="primary"
|
||||
label="ออกจากระบบ"
|
||||
push
|
||||
size="sm"
|
||||
v-close-popup
|
||||
@click="doLogout"
|
||||
/><!-- -->
|
||||
</div>
|
||||
|
||||
<div class="column col-12">
|
||||
<q-separator />
|
||||
<div class="column q-pb-md justify-center">
|
||||
<div class="text-overline text-grey q-px-md q-pt-sm">
|
||||
เลือกโหมด
|
||||
</div>
|
||||
<!-- <q-option-group v-model="group" :options="options" color="primary"/> -->
|
||||
<q-list dense v-for="op in options" :key="op.label">
|
||||
<q-item clickable>
|
||||
<q-item-section avatar>
|
||||
<q-avatar
|
||||
:color="op.color"
|
||||
text-color="white"
|
||||
:icon="op.icon"
|
||||
size="20px"
|
||||
font-size="12px"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section class="q-py-sm">{{
|
||||
op.label
|
||||
}}</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</q-btn-dropdown>
|
||||
</div>
|
||||
<q-btn
|
||||
size="13px"
|
||||
class="bg-blue-1"
|
||||
v-if="activeBtn() || activeBtnPlacement()"
|
||||
flat
|
||||
dense
|
||||
round
|
||||
@click="toggleBtnRight"
|
||||
aria-label="Menu"
|
||||
>
|
||||
<q-icon name="mdi-menu" class="rotate-180" size="20px" color="blue" />
|
||||
</q-btn>
|
||||
</q-toolbar>
|
||||
</q-header>
|
||||
<!-- end header -->
|
||||
|
||||
<!-- drawer -->
|
||||
<q-drawer
|
||||
side="left"
|
||||
class="text-white"
|
||||
style="background: #273238"
|
||||
v-model="drawerL"
|
||||
show-if-above
|
||||
:width="260"
|
||||
:breakpoint="1023"
|
||||
:mini="miniState"
|
||||
>
|
||||
<!-- ส่วนของเมนู mini -->
|
||||
<template v-slot:mini>
|
||||
<q-scroll-area class="fit mini-slot cursor-pointer">
|
||||
<q-toolbar class="q-py-md">
|
||||
<q-img
|
||||
src="@/assets/logo.png"
|
||||
spinner-color="white"
|
||||
style="height: 32px; max-width: 32px"
|
||||
/>
|
||||
</q-toolbar>
|
||||
<q-separator color="grey-9" />
|
||||
<!-- เมนูย่อย ตอนย่อ -->
|
||||
<q-list padding>
|
||||
<div v-for="(menuItem, index) in menuList" :key="index">
|
||||
<div v-if="role.includes(menuItem.role)">
|
||||
<q-item
|
||||
clickable
|
||||
v-ripple
|
||||
:active="link === menuItem.label"
|
||||
@click="link = menuItem.label"
|
||||
active-class="text-primary menuActiveMini text-weight-medium"
|
||||
v-if="menuItem.key == 3 || menuItem.key == 5"
|
||||
>
|
||||
<div class="row items-center no-wrap">
|
||||
<q-icon :name="menuItem.icon" size="20px" class="q-ml-md" />
|
||||
<q-icon
|
||||
name="mdi-dots-vertical"
|
||||
size="13px"
|
||||
color="grey-6"
|
||||
/>
|
||||
</div>
|
||||
<q-tooltip
|
||||
anchor="center right"
|
||||
self="center left"
|
||||
:offset="[10, 10]"
|
||||
>
|
||||
{{ menuItem.label }}
|
||||
</q-tooltip>
|
||||
<q-menu
|
||||
anchor="top right"
|
||||
self="top left"
|
||||
:offset="[5, 0]"
|
||||
style="background: #273238; z-index: 9000"
|
||||
>
|
||||
<q-list class="text-white q-py-sm">
|
||||
<div
|
||||
v-for="(subMenu, i) in menuItem.children"
|
||||
:key="i"
|
||||
:to="{ name: `${subMenu.path}` }"
|
||||
>
|
||||
<!-- เมนูย่อย 2 ชั้น -->
|
||||
<div v-if="menuItem.key == 5">
|
||||
<q-item dense clickable v-if="subMenu.key !== 5.1">
|
||||
<q-item-section
|
||||
>{{ subMenu.label }}
|
||||
</q-item-section>
|
||||
<q-item-section side>
|
||||
<q-icon name="keyboard_arrow_right" />
|
||||
</q-item-section>
|
||||
|
||||
<q-menu
|
||||
anchor="top end"
|
||||
self="top start"
|
||||
:offset="[5, 0]"
|
||||
style="background: #273238; z-index: 9000"
|
||||
>
|
||||
<q-list class="text-white q-py-sm">
|
||||
<q-item
|
||||
v-for="subMenu2 in subMenu.children"
|
||||
:key="subMenu2.label"
|
||||
:to="{ name: `${subMenu2.path}` }"
|
||||
dense
|
||||
class="q-pl-md text-body2"
|
||||
active-class="text-primary active-item text-weight-medium"
|
||||
clickable
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label>{{
|
||||
subMenu2.label
|
||||
}}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
</q-item>
|
||||
|
||||
<q-item
|
||||
v-else
|
||||
dense
|
||||
class="q-pl-md q-pr-xl text-body2"
|
||||
active-class="text-primary active-item text-weight-medium"
|
||||
clickable
|
||||
:to="{ name: `${subMenu.path}` }"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ subMenu.label }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
<!-- เมนูย่อย 1 ชั้น -->
|
||||
<div v-else>
|
||||
<q-item
|
||||
dense
|
||||
class="q-pl-md q-pr-xl text-body2"
|
||||
active-class="text-primary active-item text-weight-medium"
|
||||
clickable
|
||||
:to="{ name: `${subMenu.path}` }"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ subMenu.label }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
</div>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
</q-item>
|
||||
<q-item
|
||||
clickable
|
||||
v-ripple
|
||||
:to="{ name: `${menuItem.path}` }"
|
||||
:active="link === menuItem.label"
|
||||
@click="link = menuItem.label"
|
||||
active-class="text-primary menuActiveMini"
|
||||
v-else
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-avatar size="md" font-size="20px">
|
||||
<q-icon :name="menuItem.icon" />
|
||||
</q-avatar>
|
||||
</q-item-section>
|
||||
<q-tooltip
|
||||
anchor="center right"
|
||||
self="center left"
|
||||
:offset="[10, 10]"
|
||||
>
|
||||
{{ menuItem.label }}
|
||||
</q-tooltip>
|
||||
</q-item>
|
||||
</div>
|
||||
</div>
|
||||
</q-list>
|
||||
</q-scroll-area>
|
||||
</template>
|
||||
<!-- จบส่วนของเมนู mini -->
|
||||
|
||||
<!-- ส่วนของเมนู -->
|
||||
<q-scroll-area class="fit">
|
||||
<q-toolbar class="q-py-md">
|
||||
<q-toolbar-title shrink class="row items-center no-wrap">
|
||||
<q-img
|
||||
src="@/assets/logo.png"
|
||||
spinner-color="white"
|
||||
style="height: 40px; max-width: 40px"
|
||||
/>
|
||||
<div class="row q-ml-md">
|
||||
<div
|
||||
style="color: #ffffff; letter-spacing: 1px"
|
||||
class="text-body2 text-weight-bolder"
|
||||
>
|
||||
ระบบ<span class="text-primary">ทรัพยากรบุคคล</span>
|
||||
</div>
|
||||
<div class="text-caption text-white"> กรุงเทพมหานคร</div>
|
||||
</div>
|
||||
</q-toolbar-title>
|
||||
</q-toolbar>
|
||||
<q-separator inset color="grey-9" />
|
||||
<q-list padding>
|
||||
<div v-for="(menuItem, index) in menuList" :key="index">
|
||||
<!-- เมนูย่อย -->
|
||||
<div v-if="role.includes(menuItem.role)">
|
||||
<q-expansion-item
|
||||
group="somegroup"
|
||||
class="menuSub"
|
||||
expand-icon="mdi-chevron-down"
|
||||
expanded-icon="mdi-chevron-up"
|
||||
v-if="
|
||||
menuItem.key == 3 ||
|
||||
menuItem.key == 5 ||
|
||||
menuItem.key == 6 ||
|
||||
menuItem.key == 7 ||
|
||||
menuItem.key == 8
|
||||
"
|
||||
>
|
||||
<template v-slot:header>
|
||||
<q-item-section avatar>
|
||||
<q-avatar
|
||||
:icon="menuItem.icon"
|
||||
size="md"
|
||||
font-size="20px"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>{{ menuItem.label }}</q-item-section>
|
||||
</template>
|
||||
|
||||
<!-- เมนูย่อย 2 ชั้น (สรรหา) -->
|
||||
<div v-if="menuItem.key == 5">
|
||||
<div v-for="(subMenu, i) in menuItem.children" :key="i">
|
||||
<q-expansion-item
|
||||
switch-toggle-side
|
||||
dense-toggle
|
||||
:label="subMenu.label"
|
||||
v-if="subMenu.key !== 5.1"
|
||||
class="expan2"
|
||||
dense
|
||||
>
|
||||
<q-item
|
||||
dense
|
||||
class="menuSubHover"
|
||||
active-class="text-primary active-item text-weight-bold menuSubAct"
|
||||
clickable
|
||||
v-for="subMenu2 in subMenu.children"
|
||||
:key="subMenu2.key"
|
||||
:to="{ name: `${subMenu2.path}` }"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label class="font-400 subLabel"
|
||||
>{{ subMenu2.label }}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-expansion-item>
|
||||
<q-item
|
||||
v-else
|
||||
dense
|
||||
class="menuSubHover"
|
||||
active-class="text-primary active-item text-weight-bold menuSubAct"
|
||||
clickable
|
||||
:to="{ name: `${subMenu.path}` }"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ subMenu.label }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
</div>
|
||||
<!-- เมนูย่อย 1 ชั้น -->
|
||||
<q-item
|
||||
v-else
|
||||
dense
|
||||
class="menuSubHover"
|
||||
active-class="text-primary active-item text-weight-bold menuSubAct"
|
||||
clickable
|
||||
v-for="(subMenu, j) in menuItem.children"
|
||||
:key="j"
|
||||
:to="{ name: `${subMenu.path}` }"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label class="font-400">{{
|
||||
subMenu.label
|
||||
}}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-expansion-item>
|
||||
|
||||
<!-- เมนูปกติ -->
|
||||
<q-item
|
||||
class="text-weight-medium menu"
|
||||
:active="activeMenu(menuItem.path)"
|
||||
active-class="text-primary active-item text-weight-bold menuActive"
|
||||
:to="{ name: `${menuItem.path}` }"
|
||||
clickable
|
||||
v-ripple
|
||||
dense
|
||||
exact
|
||||
v-else
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-avatar size="md" font-size="20px">
|
||||
<q-icon
|
||||
:name="
|
||||
menuItem.key === active
|
||||
? menuItem.activeIcon
|
||||
: menuItem.icon
|
||||
"
|
||||
/>
|
||||
</q-avatar>
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section>
|
||||
<q-item-label>{{ menuItem.label }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
</div>
|
||||
</q-list>
|
||||
</q-scroll-area>
|
||||
</q-drawer>
|
||||
|
||||
<!-- drawer page registry/:id -->
|
||||
<q-drawer
|
||||
side="right"
|
||||
class="bg-grey-2"
|
||||
show-if-above
|
||||
v-if="tabScroll()"
|
||||
v-model="drawerR"
|
||||
:width="220"
|
||||
:breakpoint="1023"
|
||||
>
|
||||
<q-scroll-area class="fit">
|
||||
<q-list padding>
|
||||
<q-item
|
||||
v-for="(tabItem, index) in tabList"
|
||||
:key="index"
|
||||
:id="'tab--' + tabItem.tag"
|
||||
class="tabNative"
|
||||
active-class="text-blue-7 active-item text-weight-medium tabActive"
|
||||
:active="activeTab(tabItem.tag)"
|
||||
clickable
|
||||
v-ripple
|
||||
dense
|
||||
exact
|
||||
@click="tagClick(tabItem.tag)"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label
|
||||
><q-icon size="11px" name="mdi-circle-medium" /><span
|
||||
class="q-pl-xs"
|
||||
>{{ tabItem.label }}</span
|
||||
></q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-scroll-area>
|
||||
</q-drawer>
|
||||
|
||||
<!-- drawer page placement2/detail/:id -->
|
||||
<q-drawer
|
||||
side="right"
|
||||
class="bg-grey-2"
|
||||
show-if-above
|
||||
v-if="tabScrollPlacement()"
|
||||
v-model="drawerR"
|
||||
:width="220"
|
||||
:breakpoint="1023"
|
||||
>
|
||||
<q-scroll-area class="fit">
|
||||
<q-list padding>
|
||||
<q-item
|
||||
v-for="(tabItem, index) in tabListPlacement"
|
||||
:key="index"
|
||||
:id="'tab--' + tabItem.tag"
|
||||
class="tabNative"
|
||||
active-class="text-blue-7 active-item text-weight-medium tabActive"
|
||||
:active="activeTabPlacement(tabItem.tag)"
|
||||
clickable
|
||||
v-ripple
|
||||
dense
|
||||
exact
|
||||
@click="tagClickPlacement(tabItem.tag)"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label
|
||||
><q-icon size="11px" name="mdi-circle-medium" /><span
|
||||
class="q-pl-xs"
|
||||
>{{ tabItem.label }}</span
|
||||
></q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-scroll-area>
|
||||
</q-drawer>
|
||||
<!-- drawer -->
|
||||
|
||||
<q-page-container class="bg-grey-2">
|
||||
<q-page style="padding: 0 2%">
|
||||
<router-view :key="$route.fullPath" />
|
||||
</q-page>
|
||||
</q-page-container>
|
||||
<full-loader :visibility="loader" />
|
||||
</q-layout>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.menuSub .q-item__section--avatar,
|
||||
.menu .q-item__section--avatar {
|
||||
min-width: 0px;
|
||||
}
|
||||
.menu {
|
||||
padding-bottom: 5px;
|
||||
padding-top: 5px;
|
||||
border-radius: 0 100px 100px 0;
|
||||
margin-right: 2%;
|
||||
}
|
||||
|
||||
.menuActive {
|
||||
background: #212a2f;
|
||||
border-radius: 0 100px 100px 0;
|
||||
margin-right: 2%;
|
||||
}
|
||||
|
||||
.menuActiveMini {
|
||||
background: #212a2f;
|
||||
}
|
||||
.menuSub .q-item {
|
||||
border-radius: 0 100px 100px 0;
|
||||
margin-right: 2%;
|
||||
font-weight: 500;
|
||||
}
|
||||
.expan2 .q-item {
|
||||
padding-left: 10%;
|
||||
}
|
||||
.subLabel {
|
||||
white-space: nowrap;
|
||||
width: 160px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.font-400 {
|
||||
font-weight: 400;
|
||||
}
|
||||
.expan2 .menuSubHover {
|
||||
padding-left: 30%;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.menuSubHover {
|
||||
padding-left: 25%;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.menuSub .q-expansion-item__content {
|
||||
background: #212a2f;
|
||||
padding: 5px 0px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.tabNative {
|
||||
color: grey;
|
||||
padding-left: 8%;
|
||||
border-radius: 100px 0px 0px 100px;
|
||||
}
|
||||
|
||||
.tabActive {
|
||||
padding-left: 8%;
|
||||
background: #e4f2ff;
|
||||
border-radius: 100px 0px 0px 100px;
|
||||
}
|
||||
|
||||
.q-card {
|
||||
box-shadow: 3px 3px 20px -10px rgba(151, 150, 150, 0.261) !important;
|
||||
}
|
||||
.q-card--bordered {
|
||||
border: 1px solid #ededed;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.q-menu {
|
||||
box-shadow: 3px 3px 10px 1px rgba(95, 95, 95, 0.15) !important;
|
||||
}
|
||||
|
||||
.toptitle {
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: 1%;
|
||||
}
|
||||
|
||||
.q-field--outlined .q-field__control {
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.q-field--outlined .q-field__control:before {
|
||||
border-color: #c8d3db;
|
||||
}
|
||||
.btnManu {
|
||||
min-height: 48px;
|
||||
border-radius: 0px 100px 100px 0px;
|
||||
}
|
||||
|
||||
.q-field--outlined .q-icon {
|
||||
color: #7474747f;
|
||||
}
|
||||
.q-card__actions .q-btn--rectangle {
|
||||
padding: 0 14px !important;
|
||||
}
|
||||
|
||||
/* custom scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: #d6dee1;
|
||||
border-radius: 20px;
|
||||
border: 3px solid transparent;
|
||||
background-clip: content-box;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color: #a8bbbf;
|
||||
}
|
||||
</style>
|
||||
249
src/views/TestView.vue
Normal file
249
src/views/TestView.vue
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>TEST VIEW</div>
|
||||
<q-btn color="primary" label="TEST" @click="testCancel" />
|
||||
<data-table
|
||||
:rows="rows"
|
||||
:columns="columns"
|
||||
:filter="filter"
|
||||
:visible-columns="visibleColumns"
|
||||
v-model:inputfilter="filter"
|
||||
v-model:inputvisible="visibleColumns"
|
||||
>
|
||||
<!-- :nornmalData="true" -->
|
||||
<template #columns="props">
|
||||
<q-tr :props="props">
|
||||
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
||||
{{ col.value }}
|
||||
</q-td>
|
||||
</q-tr>
|
||||
</template>
|
||||
</data-table>
|
||||
|
||||
<FullCalendar
|
||||
ref="fullCalendar"
|
||||
class="demo-app-calendar"
|
||||
:options="calendarOptions"
|
||||
>
|
||||
<template v-slot:eventContent="arg">
|
||||
<b>{{ arg.timeText }}</b>
|
||||
<i>{{ arg.event.title }}</i>
|
||||
</template>
|
||||
</FullCalendar>
|
||||
<!-- publicData เป็นสถานะ "เผยแพร่" ต้องใส่ตลอด(ถ้าไม่ใส่ จะเป็นสถานะ"ยังไม่เผยแพร่") จัดการที่ state child ได้เลย -->
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { defineComponent, ref } from "vue";
|
||||
import { useQuasar } from "quasar";
|
||||
// import { useCounterStore } from "@/stores/data";
|
||||
import { useCounterMixin } from "@/stores/mixin";
|
||||
import FullCalendar from "@fullcalendar/vue3";
|
||||
import dayGridPlugin from "@fullcalendar/daygrid";
|
||||
import timeGridPlugin from "@fullcalendar/timegrid";
|
||||
import interactionPlugin from "@fullcalendar/interaction";
|
||||
import allLocales from "@fullcalendar/core/locales-all";
|
||||
import listPlugin from "@fullcalendar/list";
|
||||
|
||||
const props = defineProps({});
|
||||
|
||||
const mixin = useCounterMixin();
|
||||
const { success } = mixin;
|
||||
const $q = useQuasar();
|
||||
const columns = ref<any>([
|
||||
{
|
||||
name: "name",
|
||||
label: "Dessert (100g serving)",
|
||||
align: "left",
|
||||
field: (row: any) => row.name,
|
||||
format: (val: any) => `${val}`,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "calories",
|
||||
align: "center",
|
||||
label: "Calories",
|
||||
field: "calories",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "fat", label: "Fat (g)", field: "fat", sortable: true },
|
||||
{ name: "carbs", label: "Carbs (g)", field: "carbs" },
|
||||
{ name: "protein", label: "Protein (g)", field: "protein" },
|
||||
{ name: "sodium", label: "Sodium (mg)", field: "sodium" },
|
||||
{
|
||||
name: "calcium",
|
||||
label: "Calcium (%)",
|
||||
field: "calcium",
|
||||
sortable: true,
|
||||
sort: (a: any, b: any) => parseInt(a, 10) - parseInt(b, 10),
|
||||
},
|
||||
{
|
||||
name: "iron",
|
||||
label: "Iron (%)",
|
||||
field: "iron",
|
||||
sortable: true,
|
||||
sort: (a: any, b: any) => parseInt(a, 10) - parseInt(b, 10),
|
||||
},
|
||||
]);
|
||||
|
||||
const rows = ref<any>([
|
||||
{
|
||||
name: "Frozen Yogurt",
|
||||
calories: 159,
|
||||
fat: 6.0,
|
||||
carbs: 24,
|
||||
protein: 4.0,
|
||||
sodium: 87,
|
||||
calcium: "14%",
|
||||
iron: "1%",
|
||||
},
|
||||
{
|
||||
name: "Ice cream sandwich",
|
||||
calories: 237,
|
||||
fat: 9.0,
|
||||
carbs: 37,
|
||||
protein: 4.3,
|
||||
sodium: 129,
|
||||
calcium: "8%",
|
||||
iron: "1%",
|
||||
},
|
||||
{
|
||||
name: "Eclair",
|
||||
calories: 262,
|
||||
fat: 16.0,
|
||||
carbs: 23,
|
||||
protein: 6.0,
|
||||
sodium: 337,
|
||||
calcium: "6%",
|
||||
iron: "7%",
|
||||
},
|
||||
{
|
||||
name: "Cupcake",
|
||||
calories: 305,
|
||||
fat: 3.7,
|
||||
carbs: 67,
|
||||
protein: 4.3,
|
||||
sodium: 413,
|
||||
calcium: "3%",
|
||||
iron: "8%",
|
||||
},
|
||||
{
|
||||
name: "Gingerbread",
|
||||
calories: 356,
|
||||
fat: 16.0,
|
||||
carbs: 49,
|
||||
protein: 3.9,
|
||||
sodium: 327,
|
||||
calcium: "7%",
|
||||
iron: "16%",
|
||||
},
|
||||
{
|
||||
name: "Jelly bean",
|
||||
calories: 375,
|
||||
fat: 0.0,
|
||||
carbs: 94,
|
||||
protein: 0.0,
|
||||
sodium: 50,
|
||||
calcium: "0%",
|
||||
iron: "0%",
|
||||
},
|
||||
{
|
||||
name: "Lollipop",
|
||||
calories: 392,
|
||||
fat: 0.2,
|
||||
carbs: 98,
|
||||
protein: 0,
|
||||
sodium: 38,
|
||||
calcium: "0%",
|
||||
iron: "2%",
|
||||
},
|
||||
{
|
||||
name: "Honeycomb",
|
||||
calories: 408,
|
||||
fat: 3.2,
|
||||
carbs: 87,
|
||||
protein: 6.5,
|
||||
sodium: 562,
|
||||
calcium: "0%",
|
||||
iron: "45%",
|
||||
},
|
||||
{
|
||||
name: "Donut",
|
||||
calories: 452,
|
||||
fat: 25.0,
|
||||
carbs: 51,
|
||||
protein: 4.9,
|
||||
sodium: 326,
|
||||
calcium: "2%",
|
||||
iron: "22%",
|
||||
},
|
||||
{
|
||||
name: "KitKat",
|
||||
calories: 518,
|
||||
fat: 26.0,
|
||||
carbs: 65,
|
||||
protein: 7,
|
||||
sodium: 54,
|
||||
calcium: "12%",
|
||||
iron: "6%",
|
||||
},
|
||||
]);
|
||||
const filter = ref<string>("");
|
||||
const visibleColumns = ref<String[]>([]);
|
||||
["name", "calories", "fat", "carbs", "protein", "sodium", "calcium", "iron"];
|
||||
const edit = ref<boolean>(false);
|
||||
const calendarOptions = ref<any>({
|
||||
plugins: [
|
||||
dayGridPlugin,
|
||||
timeGridPlugin,
|
||||
interactionPlugin, // needed for dateClick
|
||||
],
|
||||
headerToolbar: {
|
||||
left: "prev,next today",
|
||||
center: "title",
|
||||
right: "dayGridMonth,timeGridWeek,timeGridDay",
|
||||
},
|
||||
initialView: "dayGridMonth",
|
||||
initialEvents: [
|
||||
{
|
||||
id: 1,
|
||||
title:
|
||||
"All-day eventAll-day eventAll-day eventAll-day eventAll-day eventAll-day eventAll-day eventAll-day eventAll-day eventAll-day eventAll-day eventAll-day eventAll-day eventAll-day event",
|
||||
start: new Date().toISOString().replace(/T.*$/, ""),
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title:
|
||||
"Timed event Timed eventTimed eventTimed eventTimed eventTimed eventTimed eventTimed eventTimed event Timed eventTimed eventTimed eventTimed event",
|
||||
start: new Date().toISOString().replace(/T.*$/, "") + "T12:00:00",
|
||||
},
|
||||
], // alternatively, use the `events` setting to fetch from a feed
|
||||
editable: true,
|
||||
selectable: true,
|
||||
selectMirror: true,
|
||||
dayMaxEvents: true,
|
||||
weekends: true,
|
||||
// select: this.handleDateSelect,
|
||||
// eventClick: this.handleEventClick,
|
||||
// eventsSet: this.handleEvents
|
||||
/* you can update a remote database when these fire:
|
||||
eventAdd:
|
||||
eventChange:
|
||||
eventRemove:
|
||||
*/
|
||||
});
|
||||
|
||||
const testAdd = () => {
|
||||
// console.log("test");
|
||||
};
|
||||
const testCancel = () => {
|
||||
edit.value = false;
|
||||
console.log("testCancel");
|
||||
success($q, "asd");
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.fc-event {
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue