Merge branch 'develop' into devTee

# Conflicts:
#	src/api/14_KPI/api.KPI.ts
This commit is contained in:
STW_TTTY\stwtt 2024-04-19 14:19:06 +07:00
commit 7f0411e710
19 changed files with 1338 additions and 1192 deletions

View file

@ -18,23 +18,23 @@ const rows = ref<any>();
const competencyTypeOp = ref<DataOption[]>([
{
id: "ID1",
id: "HEAD",
name: "สมรรถนะหลัก",
},
{
id: "ID2",
id: "GROUP",
name: "สมรรถนะประจำกลุ่มงาน",
},
{
id: "ID3",
id: "EXECUTIVE",
name: "สมรรถนะประจำผู้บริหารกรุงเทพมหานคร",
},
{
id: "ID4",
id: "DIRECTOR",
name: "สมรรถนะเฉพาะสำหรับตำแหน่ง ผอ.เขต ผช.ผอ.เขต และหัวหน้าฝ่ายในสังกัด สนง.เขต",
},
{
id: "ID5",
id: "INSPECTOR",
name: "สมรรถนะเฉพาะสำหรับตำแหน่งผู้ตรวจราชการ กทม. และผู้ตรวจราชการ",
},
]);
@ -64,11 +64,11 @@ const visibleColumns = ref<string[]>(["competency"]);
async function getData() {
const data = [
{
id: "ID1",
id: "1",
competency: "รายการสมรรถะ 1",
},
{
id: "ID2",
id: "2",
competency: "รายการสมรรถะ 2",
},
];

View file

@ -3,21 +3,19 @@ import { ref, onMounted } from "vue";
import type { QTableProps } from "quasar";
import { useCounterMixin } from "@/stores/mixin";
import { useQuasar } from "quasar";
import { useRouter } from "vue-router";
import Header from "@/components/DialogHeader.vue";
import dialogHeader from "@/components/DialogHeader.vue";
import type { DataOption } from "@/modules/14_KPI/interface/index/Main";
import type { ResponseObject } from "@/modules/14_KPI/interface/response/KpiGroup";
import http from "@/plugins/http";
import config from "@/app.config";
const modal = ref<boolean>(false);
const router = useRouter();
const rows = ref<any>();
const rows = ref<ResponseObject[]>([]);
const groupName = ref<string>("");
const editStatus = ref<boolean>(false);
const editId = ref<string>("");
const competencyTypeOp = ref<DataOption[]>([
{
id: "ID1",
@ -42,11 +40,11 @@ const competencyTypeOp = ref<DataOption[]>([
]);
const columns = ref<QTableProps["columns"]>([
{
name: "groupName",
name: "nameGroupKPI",
align: "left",
label: "รายการกลุ่มงาน",
sortable: true,
field: "groupName",
field: "nameGroupKPI",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
@ -56,71 +54,81 @@ const columns = ref<QTableProps["columns"]>([
const $q = useQuasar();
const mixin = useCounterMixin();
const { dialogRemove, messageError, showLoader, hideLoader, success } = mixin;
const competencyType = ref<string>("ID1");
const {
dialogRemove,
dialogConfirm,
showLoader,
hideLoader,
messageError,
success,
} = mixin;
const filterKeyword = ref<string>("");
const visibleColumns = ref<string[]>(["groupName"]);
const visibleColumns = ref<string[]>(["nameGroupKPI"]);
/** ดึงข้อมูล */
async function getData() {
const data = [
{
id: "ID1",
groupName: "กลุ่มงาน 1",
},
{
id: "ID2",
groupName: "กลุ่มงาน 2",
},
];
rows.value = data;
// showLoader();
// await http
// .get(config.API.orgPrefix)
// .then(async (res) => {
// })
// .catch((err) => {
// messageError($q, err);
// })
// .finally(() => {
// hideLoader();
// });
async function fetchData() {
showLoader();
await http
.get(config.API.kpiGroup)
.then(async (res) => {
rows.value = res.data.result.data;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
async function addData() {
await http
.post(config.API.kpiGroup, {
nameGroupKPI: groupName.value,
})
.then(() => {
fetchData();
success($q, "บันทึกข้อมูลสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
async function editData(id: string) {
console.log(id);
// await http
// .put(config.API.orgPrefixId(id), {
// name: prefix.value,
// })
// .then(() => {
// getData();
// success($q, "");
// })
// .catch((err) => {
// messageError($q, err);
// })
// .finally(() => {
// hideLoader();
// });
await http
.put(config.API.kpiGroupById(id), {
nameGroupKPI: groupName.value,
})
.then(() => {
fetchData();
success($q, "บันทึกข้อมูลสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
async function deleteData(id: string) {
console.log(id);
// await http
// .delete(config.API.orgPrefixId(id))
// .then(() => {
// getData();
// success($q, "");
// })
// .catch((err) => {
// messageError($q, err);
// })
// .finally(() => {
// hideLoader();w
// });
await http
.delete(config.API.kpiGroupById(id))
.then(() => {
fetchData();
success($q, "ลบข้อมูลสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/** เปลี่ยนเป็นหน้าเพิ่มข้อมูล */
@ -128,42 +136,38 @@ function onAdd() {
modal.value = true;
}
function close() {
function closeDialog() {
modal.value = false;
editStatus.value = false;
groupName.value = ''
groupName.value = "";
}
function onEdit(data: any) {
modal.value = true;
editStatus.value = true;
groupName.value = data.groupName
groupName.value = data.nameGroupKPI;
editId.value = data.id;
}
function onSubmit() {
console.log("save");
close()
async function onSubmit() {
dialogConfirm(
$q,
async () => {
editStatus.value ? editData(editId.value) : addData();
closeDialog();
},
"ยืนยันการบันทึกข้อมูล",
"ต้องการยืนยันการบันทึกข้อมูลนี้หรือไม่ ?"
);
}
onMounted(async () => {
getData();
fetchData();
});
</script>
<template>
<q-toolbar style="padding: 0">
<!-- <q-select
v-model="competencyType"
outlined
label="ประเภทสมรรถนะ"
dense
option-label="name"
option-value="id"
:options="competencyTypeOp"
style="min-width: 200px"
emit-value
map-options
/> -->
<q-btn flat round color="primary" icon="add" @click="onAdd()">
<q-tooltip> เพมขอม </q-tooltip>
</q-btn>
@ -210,15 +214,11 @@ onMounted(async () => {
</template>
<template v-slot:body="props">
<q-tr :props="props" class="cursor-pointer">
<q-td
v-for="col in props.cols"
:key="col.id"
@click="onEdit(props.row)"
>
<q-td v-for="col in props.cols" :key="col.id">
{{ col.value }}
</q-td>
<q-td auto-width>
<!-- <q-btn
<q-btn
color="edit"
flat
dense
@ -227,17 +227,10 @@ onMounted(async () => {
size="12px"
icon="edit"
clickable
@click.stop="
() => {
dialogStatus = 'edit';
dialog = true;
prefix = props.row.name;
editId = props.row.id;
}
"
@click="onEdit(props.row)"
>
<q-tooltip>แกไขขอม</q-tooltip>
</q-btn> -->
</q-btn>
<q-btn
color="red"
flat
@ -261,9 +254,9 @@ onMounted(async () => {
<q-dialog v-model="modal" persistent>
<q-card flat bordered style="min-width: 50vh">
<q-form greedy @submit.prevent @validation-success="onSubmit">
<Header
<dialog-header
:tittle="editStatus ? 'แก้ไขกลุ่มงาน' : 'เพิ่มกลุ่มงาน'"
:close="close"
:close="closeDialog"
/>
<q-separator />
<q-card-section>

View file

@ -2,11 +2,12 @@
import { ref, reactive } from "vue";
import { useRouter } from "vue-router";
import FormMain from "@/modules/14_KPI/components/competency/Forms/01_FormMain.vue";
import FormGroup from "@/modules/14_KPI/components/competency/Forms/02_FormGroup.vue";
import FormExecutive from "@/modules/14_KPI/components/competency/Forms/03_FormExecutive.vue";
import FormExecutivePosition from "@/modules/14_KPI/components/competency/Forms/04_FormExecutivePosition.vue";
import FormExecutiveLevel from "@/modules/14_KPI/components/competency/Forms/05_FormExecutiveLevel.vue";
import Main from "@/modules/14_KPI/components/competency/Forms/Main.vue";
// import FormMain from "@/modules/14_KPI/components/competency/Forms/01_FormMain.vue";
// import FormGroup from "@/modules/14_KPI/components/competency/Forms/02_FormGroup.vue";
// import FormExecutive from "@/modules/14_KPI/components/competency/Forms/03_FormExecutive.vue";
// import FormExecutivePosition from "@/modules/14_KPI/components/competency/Forms/04_FormExecutivePosition.vue";
// import FormExecutiveLevel from "@/modules/14_KPI/components/competency/Forms/05_FormExecutiveLevel.vue";
import { useKPIDataStore } from "@/modules/14_KPI/store/KPIStore";
import type { DataOption } from "@/modules/14_KPI/interface/index/Main";
@ -29,23 +30,23 @@ const formData = reactive<FormCompetency>({
const competencyTypeOp = ref<DataOption[]>([
{
id: "ID1",
id: "HEAD",
name: "สมรรถนะหลัก",
},
{
id: "ID2",
id: "GROUP",
name: "สมรรถนะประจำกลุ่มงาน",
},
{
id: "ID3",
id: "EXECUTIVE",
name: "สมรรถนะประจำผู้บริหารกรุงเทพมหานคร",
},
{
id: "ID4",
id: "DIRECTOR",
name: "สมรรถนะเฉพาะสำหรับตำแหน่ง ผอ.เขต ผช.ผอ.เขต และหัวหน้าฝ่ายในสังกัด สนง.เขต",
},
{
id: "ID5",
id: "INSPECTOR",
name: "สมรรถนะเฉพาะสำหรับตำแหน่งผู้ตรวจราชการ กทม. และผู้ตรวจราชการ",
},
]);
@ -108,134 +109,13 @@ function onSubmit() {
/>
</div>
<FormMain v-if="store.competencyType === 'ID1'" />
<Main />
<!-- <FormMain v-if="store.competencyType === 'ID1'" />
<FormGroup v-else-if="store.competencyType === 'ID2'" />
<FormExecutive v-else-if="store.competencyType === 'ID3'" />
<FormExecutivePosition v-else-if="store.competencyType === 'ID4'" />
<FormExecutiveLevel v-else-if="store.competencyType === 'ID5'" />
<!-- <div class="col-12">
<q-input
v-model="formData.competencyName"
dense
outlined
label="ชื่อสมรรถนะ"
:rules="[(val:string) => !!val || `${'กรุณากรอกชื่อสมรรถนะ'}`,]"
hide-bottom-space
/>
</div>
<div class="col-12">
<q-input
v-model="formData.definition"
label="คำจำกัดความ"
dense
type="textarea"
outlined
:rules="[(val:string) => !!val || `${'กรุณากรอกคำจำกัดความ'}`,]"
hide-bottom-space
/>
</div>
<div class="col-12">
<q-card flat bordered>
<q-card-section class="bg-grey-4">
<div
class="row items-center text-dark text-body2 text-weight-medium"
>
<div class="col-3">
<div class="row items-center">
<div class="col-1">
<q-btn
dense
flat
round
color="primary"
icon="add"
@click="ocClickAdd"
>
<q-tooltip>เพ</q-tooltip></q-btn
>
</div>
<div class="col-11 text-center">
<span>ระดบสมรรถนะ</span>
</div>
</div>
</div>
<div class="col-4">
<span>คำอธบายระด/พฤตกรรมทคาดหว/พฤตกรรมยอย</span>
</div>
</div>
</q-card-section>
<q-card-section>
<div
class="row q-pa-sm"
v-for="(items, index) in itemsFormCard"
key="index"
>
<div
class="col-3 text-center self-center text-body1 text-weight-medium"
>
<span>{{ index + 1 }}</span>
</div>
<div class="col-9">
<q-editor
v-model="formData.level_1[index]"
:dense="$q.screen.lt.md"
min-height="5rem"
:toolbar="[
[
'bold',
'italic',
'strike',
'underline',
'subscript',
'superscript',
],
['unordered', 'ordered'],
]"
:fonts="{
arial: 'Arial',
arial_black: 'Arial Black',
comic_sans: 'Comic Sans MS',
courier_new: 'Courier New',
impact: 'Impact',
lucida_grande: 'Lucida Grande',
times_new_roman: 'Times New Roman',
verdana: 'Verdana',
}"
/>
</div>
</div>
</q-card-section>
</q-card>
</div> -->
<!-- <div class="col-12">
<q-input
v-model="formData.definition"
label="กำหนดเกณฑ์การประเมิน"
dense
type="textarea"
outlined
:rules="[(val:string) => !!val || `${'กรุณากรอกกำหนดเกณฑ์การประเมิน'}`,]"
hide-bottom-space
/>
</div> -->
<FormExecutiveLevel v-else-if="store.competencyType === 'ID5'" /> -->
</div>
</q-card-section>
<!-- <div class="text-right q-pa-sm">
<q-btn
dense
unelevated
label="บันทึก"
id="onSubmit"
type="submit"
color="public"
class="q-px-md"
>
<q-tooltip>นทกขอม</q-tooltip>
</q-btn>
</div> -->
<!-- </q-form> -->
</q-card>
</template>

View file

@ -0,0 +1,240 @@
div
<script setup lang="ts">
import { ref, reactive } from "vue";
import { useCounterMixin } from "@/stores/mixin";
import { useKPIDataStore } from "@/modules/14_KPI/store/KPIStore";
import { useRouter } from "vue-router";
import { useQuasar } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
const $q = useQuasar();
const mixin = useCounterMixin();
const { dialogConfirm, showLoader, hideLoader, success, messageError } = mixin;
const router = useRouter();
const store = useKPIDataStore();
const formData = reactive({
competencyType: "",
competencyName: "",
definition: "",
levels: [
{
level: "1",
description: "",
},
],
});
function ocClickAdd() {
// if (formData.levels.length !== 6) {
const levelName = formData.levels.length + 1;
const data = {
level: levelName.toString(),
description: "",
};
formData.levels.push(data);
formData.levels[formData.levels.length].level = levelName.toString();
// }
}
function onSubmit() {
dialogConfirm($q, () => {
const body = {
competencyType: store.competencyType,
competencyName: formData.competencyName,
definition: formData.definition,
levels: formData.levels,
};
// showLoader()
// http
// .put(config.API.???,body)
// .then((res)=>{
// success($q,'')
// router.push(`/KPI-competency`)
// }).catch((e)=>{
// messageError($q,e)
// }).finally(()=>{
// hideLoader()
// })
console.log(body);
});
}
</script>
<template>
<q-form greedy @submit.prevent @validation-success="onSubmit" class="col-12">
<div class="row">
<div class="col-12">
<q-input
v-model="formData.competencyName"
dense
outlined
label="ชื่อสมรรถนะ"
:rules="[(val:string) => !!val || `${'กรุณากรอกชื่อสมรรถนะ'}`,]"
hide-bottom-space
/>
</div>
<q-card-section class="col-12 q-px-none">
<div>
<q-field
class="q_field_p_none"
ref="fieldRef"
v-model="formData.definition"
label-slot
borderless
:rules="[(val) => !!val || 'กรุณากรอกคำจำกัดความสมรรถนะ']"
hide-bottom-space
>
<template #control>
<q-editor
class="full-width"
v-model="formData.definition"
:dense="$q.screen.lt.md"
min-height="7rem"
placeholder="คำจำกัดความสมรรถนะ"
:toolbar="[
[
'bold',
'italic',
'strike',
'underline',
'subscript',
'superscript',
],
['unordered', 'ordered'],
]"
:fonts="{
arial: 'Arial',
arial_black: 'Arial Black',
comic_sans: 'Comic Sans MS',
courier_new: 'Courier New',
impact: 'Impact',
lucida_grande: 'Lucida Grande',
times_new_roman: 'Times New Roman',
verdana: 'Verdana',
}"
/>
</template>
</q-field>
</div>
</q-card-section>
<div class="col-12">
<q-card flat bordered>
<q-card-section class="bg-grey-4">
<div
class="row items-center text-dark text-body2 text-weight-medium"
>
<div class="col-3">
<div class="row items-center">
<div class="col-1">
<q-btn
dense
flat
round
color="primary"
icon="add"
@click="ocClickAdd"
>
<q-tooltip>เพ</q-tooltip></q-btn
>
</div>
<div class="col-11 text-center">
<span>ระดบสมรรถนะ</span>
</div>
</div>
</div>
<div class="col-4">
<span>พฤตกรรมทคาดหว/พฤตกรรมยอย</span>
</div>
</div>
</q-card-section>
<q-card-section>
<div
class="row q-pa-sm"
v-for="(items, index) in formData.levels"
key="index"
>
<div class="col-3 align-center q-pr-lg">
<q-input
:readonly="
store.competencyType === 'HEAD' ||
store.competencyType === 'GROUP'
"
v-model="formData.levels[index].level"
dense
outlined
:rules="[(val:string) => !!val || `${'กรุณากรอกระดับสมรรถนะ'}`,]"
hide-bottom-space
/>
</div>
<div class="col-9">
<q-field
class="q_field_p_none"
ref="fieldRef"
v-model="formData.levels[index].description"
label-slot
borderless
:rules="[
(val) =>
!!val || 'กรุณากรอกพฤติกรรมที่คาดหวัง/พฤติกรรมย่อย',
]"
hide-bottom-space
>
<template #control>
<q-editor
class="full-width"
v-model="formData.levels[index].description"
:dense="$q.screen.lt.md"
min-height="5rem"
:toolbar="[
[
'bold',
'italic',
'strike',
'underline',
'subscript',
'superscript',
],
['unordered', 'ordered'],
]"
:fonts="{
arial: 'Arial',
arial_black: 'Arial Black',
comic_sans: 'Comic Sans MS',
courier_new: 'Courier New',
impact: 'Impact',
lucida_grande: 'Lucida Grande',
times_new_roman: 'Times New Roman',
verdana: 'Verdana',
}"
/>
</template>
</q-field>
</div>
</div>
</q-card-section>
</q-card>
</div>
<div class="col-12 q-my-sm"><q-separator /></div>
<div class="col-12 row justify-end">
<q-btn
dense
unelevated
label="บันทึก"
color="public"
class="q-px-md"
type="submit"
>
<q-tooltip>นทกขอม</q-tooltip>
</q-btn>
</div>
</div>
</q-form>
</template>
<style scoped></style>

View file

@ -101,11 +101,15 @@ function updateSelected(data: any) {
planData.strategyChildPlannedId = data.id;
planData.strategyChildPlannedNode = data.level;
}
function updateSelectedAgency(data: any) {
planData.agencyId = data.orgTreeId;
planData.agencyLevel = data.orgLevel;
}
onMounted(() => {
onMounted(async () => {
// fetchData();
fetchTree();
fetchOrganizationActive();
await fetchTree();
await fetchOrganizationActive();
setTimeout(async () => {
store.activeId && (await fetchDataTree(store.activeId));
}, 200);
@ -116,38 +120,6 @@ onMounted(() => {
<q-form @submit.prevent greedy @validation-success="onSubmit()">
<div>
<div class="row q-col-gutter-md q-pa-md">
<div class="col-8">
<q-input
outlined
v-model="planData.tree"
label="หน่วยงาน/ส่วนราชการ"
bg-color="white"
dense
class="inputgreen"
:rules="[(val) => !!val || `${'หน่วยงาน/ส่วนราชการ'}`]"
hide-bottom-space
/>
</div>
<div class="col-2">
<q-select
dense
outlined
v-model="planData.round"
:options="roundOp"
label="รอบการประเมิน"
hide-bottom-space
option-label="name"
option-value="id"
map-options
emit-value
lazy-rules
class="inputgreen"
:rules="[
(val:string) =>
!!val || `${'กรุณาเลือกรอบการประเมิน'}`,
]"
/>
</div>
<div class="col-2">
<datepicker
menu-class-name="modalfix"
@ -179,7 +151,27 @@ onMounted(() => {
</template>
</datepicker>
</div>
<div class="col-3">
<div class="col-2">
<q-select
dense
outlined
v-model="planData.round"
:options="roundOp"
label="รอบการประเมิน"
hide-bottom-space
option-label="name"
option-value="id"
map-options
emit-value
lazy-rules
class="inputgreen"
:rules="[
(val:string) =>
!!val || `${'กรุณาเลือกรอบการประเมิน'}`,
]"
/>
</div>
<div class="col-2">
<q-input
outlined
v-model="planData.Data1"
@ -257,11 +249,11 @@ onMounted(() => {
<q-input
outlined
v-model="planData.point5"
label="ระดับคะแนน"
label="กรอกผลสำเร็จของงาน"
bg-color="white"
dense
class="inputgreen"
:rules="[(val) => !!val || `${'กรุณากรอกระดับคะแนน'}`]"
:rules="[(val) => !!val || `${'กรุณากรอกผลสำเร็จของงาน'}`]"
hide-bottom-space
/>
</div>
@ -274,11 +266,11 @@ onMounted(() => {
<q-input
outlined
v-model="planData.point4"
label="ระดับคะแนน"
label="กรอกผลสำเร็จของงาน"
bg-color="white"
dense
class="inputgreen"
:rules="[(val) => !!val || `${'กรุณากรอกระดับคะแนน'}`]"
:rules="[(val) => !!val || `${'กรุณากรอกผลสำเร็จของงาน'}`]"
hide-bottom-space
/>
</div>
@ -291,11 +283,11 @@ onMounted(() => {
<q-input
outlined
v-model="planData.point3"
label="ระดับคะแนน"
label="กรอกผลสำเร็จของงาน"
bg-color="white"
dense
class="inputgreen"
:rules="[(val) => !!val || `${'กรุณากรอกระดับคะแนน'}`]"
:rules="[(val) => !!val || `${'กรุณากรอกผลสำเร็จของงาน'}`]"
hide-bottom-space
/>
</div>
@ -308,11 +300,11 @@ onMounted(() => {
<q-input
outlined
v-model="planData.point2"
label="ระดับคะแนน"
label="กรอกผลสำเร็จของงาน"
bg-color="white"
dense
class="inputgreen"
:rules="[(val) => !!val || `${'กรุณากรอกระดับคะแนน'}`]"
:rules="[(val) => !!val || `${'กรุณากรอกผลสำเร็จของงาน'}`]"
hide-bottom-space
/>
</div>
@ -325,11 +317,11 @@ onMounted(() => {
<q-input
outlined
v-model="planData.point1"
label="ระดับคะแนน"
label="กรอกผลสำเร็จของงาน"
bg-color="white"
dense
class="inputgreen"
:rules="[(val) => !!val || `${'กรุณากรอกระดับคะแนน'}`]"
:rules="[(val) => !!val || `${'กรุณากรอกผลสำเร็จของงาน'}`]"
hide-bottom-space
/>
</div>
@ -367,7 +359,7 @@ onMounted(() => {
<div
class="col-xs-12 col-sm-12 text-weight-medium bg-grey-1 q-py-xs q-px-md"
>
หนวยงาน
หนวยงาน/วนราชการ
</div>
<q-separator />
@ -384,11 +376,12 @@ onMounted(() => {
</template>
</q-input>
<q-tree
style="height: 350px; overflow: scroll"
dense
:nodes="nodeAgency"
node-key="orgTreeId"
label-key="labelName"
default-expand-all
selected-color="primary"
:filter="filterAgency"
:no-results-label="notFound"
:no-nodes-label="noData"
@ -397,8 +390,8 @@ onMounted(() => {
<template v-slot:default-header="prop">
<q-item
clickable
@click.stop="updateSelectedAgency(prop.node)"
:active="nodeId == prop.node.orgTreeId"
@click.stop="updateSelected(prop.node)"
active-class="my-list-link text-primary text-weight-medium"
class="row col-12 items-center text-dark q-py-xs q-pl-sm rounded-borders my-list"
>
@ -445,6 +438,7 @@ onMounted(() => {
</template>
</q-input>
<q-tree
style="height: 350px; overflow: scroll"
dense
:nodes="nodeplan"
selected-color="primary"

View file

@ -7,6 +7,7 @@ interface FormQueryRound {
interface FormRound {
durationKPI: string;
year: number | null;
startDate: Date | null;
endDate: Date | null;
}

View file

@ -0,0 +1,7 @@
//ข้อมูล
interface ResponseObject {
nameGroupKPI: string,
}
export type { ResponseObject };

View file

@ -3,7 +3,7 @@ import { ref } from "vue";
// store
export const useKPIDataStore = defineStore("KPIDataStore", () => {
const competencyType = ref<string>("ID1");
const competencyType = ref<string>("HEAD");
return { competencyType };
});

View file

@ -5,11 +5,13 @@ import { useRouter } from "vue-router";
/** importStore*/
import { useCounterMixin } from "@/stores/mixin";
import http from "@/plugins/http";
import config from "@/app.config";
/** use*/
const $q = useQuasar();
const router = useRouter();
const { showLoader, hideLoader, dialogRemove, success } = useCounterMixin();
const { showLoader, hideLoader, dialogRemove, success, messageError } =
useCounterMixin();
/** หัวตาราง */
const rows = ref<any>([]);
@ -42,6 +44,10 @@ const columns = ref<QTableProps["columns"]>([
style: "font-size: 14px",
},
]);
const node = ref<any>([]);
const expanded = ref<any>([]);
const filter = ref<string>("");
const filterMain = ref<string>("");
const visibleColumns = ref<string[]>([
"indicatorNo",
"indicatorPass",
@ -66,6 +72,11 @@ const formFilter = reactive({
keyword: "",
});
const nodeData = reactive<any>({
node: null,
nodeId: null,
});
function fetchList() {
showLoader();
const data = [
@ -101,8 +112,49 @@ function onClickDelete(id: number) {
});
}
function fetchActive() {
showLoader();
http
.get(config.API.activeOrganization)
.then((res) => {
const data = res.data.result;
fetchTree(data.activeId);
})
.catch((err) => {
messageError($q, err);
hideLoader();
});
}
async function fetchTree(id: string) {
showLoader();
http
.get(config.API.orgByid(id.toString()))
.then((res) => {
const data = res.data.result;
node.value = data;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
function updateSelectedTreeMain(data: any) {
if (nodeData.node === data.orgLevel && nodeData.nodeId === data.orgTreeId) {
nodeData.node = null;
nodeData.nodeId = null;
} else {
nodeData.node = data.orgLevel;
nodeData.nodeId = data.orgTreeId;
}
}
onMounted(() => {
fetchList();
fetchActive();
});
</script>
@ -111,139 +163,207 @@ onMounted(() => {
รายการตวชดตามแผนฯ
</div>
<q-card flat bordered class="q-pa-md">
<q-toolbar class="q-pa-none">
<div class="row q-gutter-x-sm">
<div>
<q-select
dense
outlined
v-model="formFilter.org"
:options="orgOp"
label="หน่วยงาน/ส่วนราชการ"
option-label="name"
option-value="id"
emit-value
map-options
/>
</div>
<div>
<q-select
dense
outlined
v-model="formFilter.round"
:options="roundOp"
label="รอบการประเมิน"
option-label="name"
option-value="id"
emit-value
map-options
/>
</div>
</div>
<q-toolbar-title>
<q-btn
flat
round
dense
icon="add"
color="primary"
@click="onClickAddOrView()"
>
<q-tooltip>เพ</q-tooltip>
</q-btn>
</q-toolbar-title>
<q-space />
<div class="row q-gutter-sm">
<div>
<q-input
standout
dense
v-model="formFilter.keyword"
ref="filterRef"
outlined
debounce="300"
placeholder="ค้นหา"
>
<template v-slot:append>
<q-icon v-if="formFilter.keyword == ''" name="search" />
<q-icon
v-if="formFilter.keyword !== ''"
name="clear"
class="cursor-pointer"
@click="formFilter.keyword = ''"
/>
</template>
</q-input>
</div>
<div>
<q-select
v-model="visibleColumns"
multiple
outlined
dense
options-dense
:display-value="$q.lang.table.columns"
emit-value
map-options
:options="columns"
option-value="name"
options-cover
style="min-width: 150px"
/>
</div>
</div>
</q-toolbar>
<div class="col-12">
<d-table
for="table"
ref="table"
:columns="columns"
:rows="rows"
row-key="subject"
flat
bordered
dense
class="custom-header-table"
:visible-columns="visibleColumns"
>
<template v-slot:header="props">
<q-tr :props="props">
<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 />
</q-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props" class="cursor-pointer">
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
@click="onClickAddOrView(true, props.row.id)"
>
<div class="table_ellipsis">
{{ col.value ? col.value : "-" }}
<div class="row q-col-gutter-sm">
<q-card bordered class="col-4">
<q-card-section class="q-py-sm">
<div class="text-subtitle2 text-bold">หนวยงาน/วนราชการ</div>
</q-card-section>
<div class="col-xs-12 col-sm-3 row">
<div class="col-12 row no-wrap">
<div class="col-12 q-py-sm q-px-sm">
<div class="q-gutter-sm">
<q-input dense outlined v-model="filterMain" label="ค้นหา">
<template v-slot:append>
<q-icon
v-if="filterMain !== ''"
name="clear"
class="cursor-pointer"
@click="filterMain = ''"
/>
<q-icon v-else name="search" color="grey-5" />
</template>
</q-input>
<div>
<q-tree
class="tree-container"
dense
:nodes="node"
node-key="orgTreeName"
label-key="labelName"
v-model:expanded="expanded"
:filter="filterMain"
no-results-label="ไม่พบข้อมูลที่ค้นหา"
no-nodes-label="ไม่มีข้อมูล"
v-model:selected="nodeData.nodeId"
>
<template v-slot:default-header="prop">
<q-item
clickable
@click.stop="updateSelectedTreeMain(prop.node)"
:active="nodeData.nodeId === prop.node.orgTreeId"
active-class="my-list-link text-primary text-weight-medium"
class="row col-12 items-center text-dark q-py-xs q-pl-sm rounded-borders my-list"
>
<div>
<div class="text-weight-medium">
{{ prop.node.orgTreeName }}
</div>
<div class="text-weight-light text-grey-8">
{{
prop.node.orgCode == null
? null
: prop.node.orgCode
}}
{{
prop.node.orgTreeShortName == null
? null
: prop.node.orgTreeShortName
}}
</div>
</div>
</q-item>
</template>
</q-tree>
</div>
</div>
</q-td>
<q-td>
<q-btn
flat
round
icon="delete"
color="red"
@click.stop.pervent="onClickDelete(props.rowIndex)"
>
<q-tooltip>ลบขอม </q-tooltip>
</q-btn>
</q-td>
</q-tr>
</template>
</d-table>
</div>
<div class="col-12 row">
<q-separator :vertical="!$q.screen.lt.md" />
</div>
</div>
</div>
</q-card>
<div class="col-8">
<div class="row q-col-gutter-sm q-mb-sm">
<div class="col-3">
<q-select
dense
outlined
v-model="formFilter.round"
:options="roundOp"
label="รอบการประเมิน"
option-label="name"
option-value="id"
emit-value
map-options
/>
</div>
<div class="col-2">
<q-btn
flat
round
dense
icon="add"
color="primary"
@click="onClickAddOrView()"
>
<q-tooltip>เพ</q-tooltip>
</q-btn>
</div>
<div class="col-4">
<q-input
standout
dense
v-model="formFilter.keyword"
ref="filterRef"
outlined
debounce="300"
placeholder="ค้นหา"
>
<template v-slot:append>
<q-icon v-if="formFilter.keyword == ''" name="search" />
<q-icon
v-if="formFilter.keyword !== ''"
name="clear"
class="cursor-pointer"
@click="formFilter.keyword = ''"
/>
</template>
</q-input>
</div>
<div class="col-3">
<q-select
v-model="visibleColumns"
multiple
outlined
dense
options-dense
:display-value="$q.lang.table.columns"
emit-value
map-options
:options="columns"
option-value="name"
options-cover
style="min-width: 150px"
/>
</div>
</div>
<div class="col-12">
<d-table
for="table"
ref="table"
:columns="columns"
:rows="rows"
row-key="subject"
flat
bordered
dense
class="custom-header-table"
:visible-columns="visibleColumns"
>
<template v-slot:header="props">
<q-tr :props="props">
<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 />
</q-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props" class="cursor-pointer">
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
@click="onClickAddOrView(true, props.row.id)"
>
<div class="table_ellipsis">
{{ col.value ? col.value : "-" }}
</div>
</q-td>
<q-td>
<q-btn
flat
round
icon="delete"
color="red"
@click.stop.pervent="onClickDelete(props.rowIndex)"
>
<q-tooltip>ลบขอม </q-tooltip>
</q-btn>
</q-td>
</q-tr>
</template>
</d-table>
</div>
</div>
</div>
</q-card>
</template>
<style scoped></style>
<style lang="scss" scoped>
.tree-container {
overflow: auto;
height: 65vh;
border: 1px solid #e6e6e7;
border-radius: 10px;
}
.my-list-link {
color: rgb(118, 168, 222);
border-radius: 5px;
background: #a3d3fb48 !important;
font-weight: 600;
border: 1px solid rgba(175, 185, 196, 0.217);
}
</style>

View file

@ -70,17 +70,32 @@ const columns = ref<QTableProps["columns"]>([
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "isActive",
align: "left",
label: "สถานะ",
sortable: true,
field: "isActive",
format: (val) => (val ? "เปิด" : "ปิดแล้ว"),
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
const visibleColumns = ref<string[]>([
"durationKPI",
"startDate",
"endDate",
"isActive",
]);
const visibleColumns = ref<string[]>(["durationKPI", "startDate", "endDate"]);
/** itemMenu*/
const itemMenu = ref<ItemsMenu[]>([
{
label: "เปิดรอบ",
value: "open",
icon: "mdi-check",
color: "primary",
},
// {
// label: "",
// value: "open",
// icon: "mdi-check",
// color: "primary",
// },
{
label: "ปิดรอบ",
value: "close",
@ -113,6 +128,7 @@ const formQuery = reactive<FormQueryRound>({
const totalList = ref<number>(1);
const formData = reactive<FormRound>({
durationKPI: "",
year: null,
startDate: null,
endDate: null,
});
@ -172,6 +188,7 @@ function clearFormData() {
formData.durationKPI = "";
formData.startDate = null;
formData.endDate = null;
formData.year = null;
}
/** function บันทึกข้อมูลเพิ่มรอบการประเมิน*/
@ -244,6 +261,7 @@ function onCloseRounde(id: string) {
dialogConfirm(
$q,
() => {
showLoader();
http
.get(config.API.kpiPeriod + `/close/${id}`)
.then(() => {
@ -336,7 +354,9 @@ onMounted(() => {
dense
lazy-rules
outlined
:model-value="Number(formQuery.year) + 543"
:model-value="
formQuery.year === 0 ? 'ทั้งหมด' : Number(formQuery.year) + 543
"
:label="`${'ปีงบประมาณ'}`"
>
<template v-slot:prepend>
@ -347,6 +367,15 @@ onMounted(() => {
>
</q-icon>
</template>
<template v-if="formQuery.year" v-slot:append>
<q-icon
name="cancel"
@click.stop.prevent="
(formQuery.year = 0), (formQuery.page = 1), fetchList()
"
class="cursor-pointer"
/>
</template>
</q-input>
</template>
</datepicker>
@ -462,7 +491,9 @@ onMounted(() => {
<q-item
clickable
v-close-popup
v-for="items in itemMenu"
v-for="items in props.row.isActive
? itemMenu
: itemMenu.slice(1, 2)"
@click="onClickAction(items.value, props.row.id)"
>
<q-item-section avatar>
@ -526,6 +557,49 @@ onMounted(() => {
]"
/>
</div>
<div class="col-12">
<datepicker
menu-class-name="modalfix"
v-model="formData.year"
:locale="'th'"
autoApply
year-picker
:enableTimePicker="false"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
dense
outlined
hide-bottom-space
class="inputgreen"
:model-value="
formData.year === null
? null
: Number(formData.year) + 543
"
:label="`${'ปีงบประมาณ'}`"
:rules="[
(val:string) =>
!!val || `${'กรุณาเลือกปีงบประมาณ'}`,
]"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-12">
<datepicker
menu-class-name="modalfix"