Merge branch 'develop' into devTee

This commit is contained in:
STW_TTTY\stwtt 2024-04-29 14:10:54 +07:00
commit 7ae3bf5774
19 changed files with 482 additions and 80 deletions

View file

@ -9,12 +9,14 @@ const kpiPlan = `${env.API_URI}/kpi/plan`;
const kpiCapacity = `${env.API_URI}/kpi/capacity`;
const kpiLink = `${env.API_URI}/kpi/link`;
const KpiUser = `${env.API_URI}/kpi/user`;
const KpiFile = `${env.API_URI}/salary/file`;
export default {
KPI,
/** รอบการประเมินผล*/
kpiPeriod,
kpiPeriodById: (id: string) => `${kpiPeriod}/${id}`,
kpiEvaluation,
kpiFile: KpiFile,
/** role */
kpiRoleMainList: `${KPI}/role`,

View file

@ -46,6 +46,10 @@ const props = defineProps({
require: true,
},
fetchStatCard: { type: Function, require: true },
typeCommand: {
type: String,
require: true,
},
});
/** Tree*/
@ -137,6 +141,7 @@ async function fetchDataTable(id: string, level: number = 0) {
node: level,
nodeId: id,
position: props?.dataRow?.positionCandidate,
typeCommand: props.typeCommand,
};
await http
.post(config.API.orgPosPlacement, body)
@ -217,6 +222,7 @@ async function onClickSubmit() {
orgTreeShortName: dataNode.orgTreeShortName, //
posPath: selectedPos.value[0].positionName, //
posNumber: dataPosMaster.posMasterNo, //()
typeCommand: props.typeCommand,
};
await http

View file

@ -262,7 +262,7 @@ function convertDraft(val: boolean) {
}
}
/**เรียกข้อมูลรายชื่อผู้สอบผ่า */
/**เรียกข้อมูลรายชื่อผู้สอบผ่า */
async function getTable() {
showLoader();
await http
@ -493,8 +493,13 @@ const editDetail = (
* @param pid id personal
*/
const modalDialogSelectOrg = ref<boolean>(false);
const typeCommand = ref<string>("");
const dataRow = ref<DataList>();
function openAppointModal(pid: string, data: DataList) {
function openAppointModal(
pid: string,
data: DataList,
typeCommandVal: "APPOINTED" | "APPOINT" | "SLIP" | "MOVE"
) {
// appointModal.value = true;
// personalId.value = pid;
// personal.value = dataRes.value.filter(
@ -503,6 +508,7 @@ function openAppointModal(pid: string, data: DataList) {
// console.log(personal.value);
dataRow.value = data;
typeCommand.value = typeCommandVal;
modalDialogSelectOrg.value = !modalDialogSelectOrg.value;
}
@ -623,6 +629,7 @@ onMounted(async () => {
await getTable();
});
</script>
<template>
<q-form ref="myForm">
<Table
@ -772,7 +779,13 @@ onMounted(async () => {
"
clickable
v-close-popup
@click="openAppointModal(props.row.personalId, props.row)"
@click="
openAppointModal(
props.row.personalId,
props.row,
'APPOINTED'
)
"
>
<q-item-section
style="min-width: 0px"
@ -785,7 +798,90 @@ onMounted(async () => {
name="mdi-bookmark-outline"
/>
</q-item-section>
<q-item-section>เลอกหนวยงานทบบรรจ</q-item-section>
<q-item-section
>เลอกหนวยงานทบบรรจและแตงต</q-item-section
>
</q-item>
<q-item
v-if="
(roleAdmin && props.row.statusId === 'UN-CONTAIN') ||
(props.row.draft === 'รอส่งตัว' &&
props.row.statusId !== 'DISCLAIM')
"
clickable
v-close-popup
@click="
openAppointModal(
props.row.personalId,
props.row,
'APPOINT'
)
"
>
<q-item-section
style="min-width: 0px"
avatar
class="q-py-sm"
>
<q-icon
color="primary"
size="xs"
name="mdi-bookmark-outline"
/>
</q-item-section>
<q-item-section>เลอกหนวยงานทบแตงต</q-item-section>
</q-item>
<q-item
v-if="
(roleAdmin && props.row.statusId === 'UN-CONTAIN') ||
(props.row.draft === 'รอส่งตัว' &&
props.row.statusId !== 'DISCLAIM')
"
clickable
v-close-popup
@click="
openAppointModal(props.row.personalId, props.row, 'SLIP')
"
>
<q-item-section
style="min-width: 0px"
avatar
class="q-py-sm"
>
<q-icon
color="primary"
size="xs"
name="mdi-bookmark-outline"
/>
</q-item-section>
<q-item-section>เลอกหนวยงานทบเลอน</q-item-section>
</q-item>
<q-item
v-if="
(roleAdmin && props.row.statusId === 'UN-CONTAIN') ||
(props.row.draft === 'รอส่งตัว' &&
props.row.statusId !== 'DISCLAIM')
"
clickable
v-close-popup
@click="
openAppointModal(props.row.personalId, props.row, 'MOVE')
"
>
<q-item-section
style="min-width: 0px"
avatar
class="q-py-sm"
>
<q-icon
color="primary"
size="xs"
name="mdi-bookmark-outline"
/>
</q-item-section>
<q-item-section>เลอกหนวยงานทบยาย</q-item-section>
</q-item>
<q-separator />
@ -1231,6 +1327,7 @@ onMounted(async () => {
:dataRow="dataRow"
:fetchTable="getTable"
:fetchStatCard="statCard"
:typeCommand="typeCommand"
/>
</template>

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, reactive,watch } from "vue";
import { ref, onMounted, reactive, watch } from "vue";
import type { QTableProps } from "quasar";
import { useCounterMixin } from "@/stores/mixin";
import { useQuasar } from "quasar";
@ -14,11 +14,9 @@ import { useKPIDataStore } from "@/modules/14_KPI/store/KPIStore";
import http from "@/plugins/http";
import config from "@/app.config";
import type {
NewPagination,
} from "@/modules/14_KPI/interface/index/Main";
import type { NewPagination } from "@/modules/14_KPI/interface/index/Main";
const total = ref<number>()
const total = ref<number>();
const store = useKPIDataStore();
const router = useRouter();
const $q = useQuasar();
@ -76,10 +74,10 @@ async function fetchList() {
await http
.get(
config.API.kpiCapacity +
`?page=${formQuery.page}&pageSize=${formQuery.pageSize}&keyword=${formQuery.keyword}&type=${store.competencyType}`
`?page=${formQuery.page}&pageSize=${formQuery.pageSize}&keyword=${formQuery.keyword}&type=${store.competencyTypeVal}`
)
.then(async (res) => {
total.value = res.data.result.total
total.value = res.data.result.total;
const data: ResDataCapacity[] = res.data.result.data;
totalList.value = Math.ceil(res.data.result.total / formQuery.pageSize);
rows.value = data;
@ -127,7 +125,7 @@ function fetchNewList() {
* function updatePagination
* @param newPagination อม Pagination ใหม
*/
function updatePagination(newPagination: NewPagination) {
function updatePagination(newPagination: NewPagination) {
formQuery.page = 1;
formQuery.pageSize = newPagination.rowsPerPage;
}
@ -147,7 +145,7 @@ onMounted(() => {
<template>
<q-toolbar style="padding: 0">
<q-select
v-model="store.competencyType"
v-model="store.competencyTypeVal"
outlined
label="ประเภทสมรรถนะ"
dense

View file

@ -95,7 +95,7 @@ function onSubmit() {
<div class="row q-col-gutter-sm">
<div class="col-12">
<q-select
v-model="store.competencyType"
v-model="store.competencyTypeVal"
outlined
label="เลือกประเภทสมรรถนะ"
dense

View file

@ -44,7 +44,7 @@ function ocClickAdd() {
function onSubmit() {
dialogConfirm($q, () => {
const body = {
competencyType: store.competencyType,
competencyType: store.competencyTypeVal,
competencyName: formData.competencyName,
definition: formData.definition,
levels: formData.levels,

View file

@ -55,7 +55,7 @@ const formData = reactive<FormGroup>({
function onSubmit() {
dialogConfirm($q, () => {
const body = {
competencyType: store.competencyType,
competencyType: store.competencyTypeVal,
competencyName: formData.definition,
definition: formData.definition,
levels1: formScore.score1,

View file

@ -12,7 +12,7 @@ const $q = useQuasar();
const { dialogConfirm, showLoader, success, hideLoader, messageError } =
useCounterMixin();
const router = useRouter
const router = useRouter;
const store = useKPIDataStore();
const formData = reactive({
competencyType: "",
@ -80,30 +80,28 @@ function updateSelectType(val: string, index: number) {
formData.form[index].posLevel = "";
}
function onSubmit() {
dialogConfirm($q, () => {
const body = {
competencyType:store.competencyType,
competencyName:formData.competencyName,
definition:formData.definition,
postype:formData.form,
evaluation:formData.evaluation,
}
// showLoader()
// http
// .put(config.API.???,body)
// .then((res)=>{
// success($q,'')
// router.push(`/KPI-competency`)
// }).catch((e)=>{
// messageError($q,e)
// }).finally(()=>{
// hideLoader()
// })
console.log(body)
})
competencyType: store.competencyTypeVal,
competencyName: formData.competencyName,
definition: formData.definition,
postype: formData.form,
evaluation: formData.evaluation,
};
// showLoader()
// http
// .put(config.API.???,body)
// .then((res)=>{
// success($q,'')
// router.push(`/KPI-competency`)
// }).catch((e)=>{
// messageError($q,e)
// }).finally(()=>{
// hideLoader()
// })
console.log(body);
});
}
onMounted(() => {

View file

@ -38,7 +38,7 @@ const formData = reactive({
function onSubmit() {
dialogConfirm($q, () => {
const body = {
competencyType: store.competencyType,
competencyType: store.competencyTypeVal,
competencyName: formData.competencyName,
definition: formData.definition,
levels1: formData.level1,

View file

@ -35,7 +35,7 @@ const formData = reactive({
function onSubmit() {
dialogConfirm($q, () => {
const body = {
competencyType: store.competencyType,
competencyType: store.competencyTypeVal,
competencyName: formData.competencyName,
definition: formData.definition,
levels1: formData.level1,
@ -74,7 +74,7 @@ function onSubmit() {
<q-card-section class="col-12 q-px-none">
<div>
<q-field
class="q_field_p_none"
class="q_field_p_none"
ref="fieldRef"
v-model="formData.definition"
label-slot

View file

@ -57,7 +57,8 @@ function onClickAddLevels() {
const levelName = formData.levels.length + 1;
const data = {
level:
(store.competencyType === "HEAD" || store.competencyType === "GROUP") &&
(store.competencyTypeVal === "HEAD" ||
store.competencyTypeVal === "GROUP") &&
levelName <= 6
? levelName.toString()
: "",
@ -69,7 +70,7 @@ function onClickAddLevels() {
function onSubmit() {
dialogConfirm($q, async () => {
const formBody = {
type: store.competencyType,
type: store.competencyTypeVal,
name: formData.competencyName,
description: formData.definition,
capacityDetails: formData.levels,
@ -201,8 +202,8 @@ onMounted(() => {
<div class="col-3 align-center q-pr-lg">
<q-input
:readonly="
store.competencyType === 'HEAD' ||
store.competencyType === 'GROUP'
store.competencyTypeVal === 'HEAD' ||
store.competencyTypeVal === 'GROUP'
"
v-model="formData.levels[index].level"
dense
@ -257,11 +258,11 @@ onMounted(() => {
icon="delete"
@click="onDeleteLevels(index)"
v-if="
(store.competencyType === 'HEAD' && index > 4) ||
(store.competencyType === 'GROUP' && index > 4) ||
((store.competencyType === 'EXECUTIVE' ||
store.competencyType === 'DIRECTOR' ||
store.competencyType === 'INSPECTOR') &&
(store.competencyTypeVal === 'HEAD' && index > 4) ||
(store.competencyTypeVal === 'GROUP' && index > 4) ||
((store.competencyTypeVal === 'EXECUTIVE' ||
store.competencyTypeVal === 'DIRECTOR' ||
store.competencyTypeVal === 'INSPECTOR') &&
index > 0)
"
>

View file

@ -1,3 +1,284 @@
<script setup lang="ts">
import { ref, reactive, onMounted } from "vue";
import { useQuasar } from "quasar";
import { useRoute } from "vue-router";
import config from "@/app.config";
import http from "@/plugins/http";
import type { QTableProps } from "quasar";
// import type { FormComment } from "@/modules/08_KPI/interface/request/index";
import type { ResEvaluator } from "@/modules/14_KPI/interface/response/Main";
import DialogHeader from "@/components/DialogHeader.vue";
import { useCounterMixin } from "@/stores/mixin";
const $q = useQuasar();
const route = useRoute();
const { showLoader, hideLoader, messageError, dialogConfirm, success } =
useCounterMixin();
const evaluatorId = ref<string>(route.params.id.toString());
const isReadonly = <boolean>(route.name === "KPIEditEvaluator" ? true : false);
const props = defineProps({
type: {
type: String,
require: true,
},
});
/** Table*/
const visibleColumns = ref<string[]>(["topic", "reason"]);
const columns = ref<QTableProps["columns"]>([
{
name: "topic",
align: "left",
label: "หัวข้อ",
sortable: true,
field: "topic",
headerStyle: "font-size: 14px",
style: "font-size: 14px;",
},
{
name: "reason",
align: "left",
label: "ความคิดเห็น",
sortable: true,
field: "reason",
headerStyle: "font-size: 14px",
style: "font-size: 14px;",
},
]);
const rows = ref<ResEvaluator[]>([]);
const filterKeyword = ref<string>("");
const modal = ref<boolean>(false);
// const formComment = reactive<FormComment>({
// topic: "",
// reason: "",
// });
// const optionTopicMain = ref<string[]>([
// " ",
// "",
// "",
// "",
// "",
// "",
// ]);
// const optionTopic = ref<string[]>(optionTopicMain.value);
function fetchList() {
showLoader();
http
.get(config.API.kpiUserEvaluation + `/${props.type}/${evaluatorId.value}`)
.then((res) => {
rows.value = res.data.result;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
// function openDialog() {
// modal.value = true;
// }
// function closeDialog() {
// modal.value = false;
// formComment.topic = "";
// formComment.reason = "";
// }
// function createValue(val: string, done: Function) {
// if (val.length > 0) {
// if (!optionTopic.value.includes(val)) {
// optionTopic.value.push(val);
// }
// done(val);
// }
// }
// function filterFn(val: string, update: Function) {
// update(() => {
// optionTopic.value = optionTopicMain.value.filter(
// (v: string) => v.indexOf(val) > -1
// );
// });
// }
// function onSubmit() {
// dialogConfirm($q, () => {
// showLoader();
// http
// .put(
// config.API.kpiUserEvaluation + `/${props.type}/${evaluatorId.value}`,
// formComment
// )
// .then(() => {
// fetchList();
// closeDialog();
// success($q, "");
// })
// .catch((err) => {
// messageError($q, err);
// })
// .finally(() => {
// hideLoader();
// });
// });
// }
const pagination = ref({
sortBy: "desc",
descending: false,
page: 1,
rowsPerPage: 10,
});
onMounted(() => {
fetchList();
});
</script>
<template>
<div class="q-pa-md">ประเม</div>
<div class="q-pa-md">
<q-toolbar style="padding: 0px">
<q-btn v-if="isReadonly" flat round dense icon="add" color="blue-4">
<q-tooltip>เสนอความคดเห</q-tooltip>
</q-btn>
<q-space />
<div class="row q-col-gutter-sm">
<q-input
outlined
dense
debounce="300"
v-model="filterKeyword"
placeholder="ค้นหา"
>
<template v-slot:append>
<q-icon name="search" />
</template>
</q-input>
<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>
</q-toolbar>
<div class="col-12">
<d-table
ref="table"
:columns="columns"
:rows="rows"
:filter="filterKeyword"
row-key="id"
flat
bordered
dense
class="custom-table"
:visible-columns="visibleColumns"
:rows-per-page-options="[10, 20, 50, 100]"
no-data-label="ไม่มีข้อมูล"
v-model:pagination="pagination"
>
<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-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props" class="cursor-pointer">
<q-td v-for="col in props.cols" :key="col.id" style="width: 50%">
{{ col.value ? col.value : "-" }}
</q-td>
</q-tr>
</template>
<template v-slot:pagination="scope">
งหมด {{ rows.length }} รายการ
<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>
</d-table>
</div>
</div>
<!-- <q-dialog v-model="modal" persistent>
<q-card style="width: 700px; max-width: 80vw">
<DialogHeader :tittle="'เสนอความคิดเห็น'" :close="closeDialog" />
<q-separator />
<q-form greedy @submit.prevent @validation-success="onSubmit">
<q-card-section>
<div class="row q-col-gutter-md">
<div class="col-12">
<q-select
class="inputgreen"
dense
outlined
v-model="formComment.topic"
use-input
input-debounce="0"
@new-value="createValue"
:options="optionTopic"
@filter="filterFn"
hide-bottom-space
lazy-rules
label="หัวข้อ"
:rules="[
(val:string) =>
!!val || `${'กรุณาเลือกหัวข้อ'}`,
]"
/>
</div>
<div class="col-12">
<q-input
v-model="formComment.reason"
class="inputgreen"
dense
outlined
type="textarea"
label="ควาดคิดเห็น"
hide-bottom-space
lazy-rules
:rules="[
(val:string) =>
!!val || `${'กรุณากรอกความคิดเห็น'}`,
]"
/>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn label="บันทึก" color="secondary" type="submit"
><q-tooltip>นทกขอม</q-tooltip></q-btn
>
</q-card-actions>
</q-form>
</q-card>
</q-dialog> -->
</template>
<style scoped></style>

View file

@ -19,6 +19,7 @@ const {
messageError,
dialogRemove,
} = useCounterMixin();
interface ArrayFileList {
id: string;
pathName: string;
@ -31,18 +32,20 @@ const documentFile = ref<any>(null);
const fileList = ref<ArrayFileList[]>([]);
async function getData() {
// showLoader();
// await http
// .get(config.API.file + `/KPI//${id.value}`)
// .then((res) => {
// fileList.value = res.data;
// })
// .catch((e) => {
// messageError($q, e);
// })
// .finally(() => {
// hideLoader();
// });
console.log(config.API.kpiFile);
showLoader();
await http
.get(config.API.kpiFile + `/KPI/ไฟล์เอกสาร/${id.value}`)
.then((res) => {
fileList.value = res.data;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
async function uploadFileDoc(uploadUrl: string, file: any) {
@ -69,7 +72,6 @@ async function uploadFileDoc(uploadUrl: string, file: any) {
}
async function clickUpload(file: any) {
// const fileName = { fileName: file.name };
// dialogConfirm(
// $q,
// async () => {
@ -106,7 +108,7 @@ async function clickUpload(file: any) {
function downloadFile(fileName: string) {
showLoader();
http
.get(config.API.file + `/KPI/ไฟล์เอกสาร/${id.value}/${fileName}`)
.get(config.API.kpiFile + `/KPI/ไฟล์เอกสาร/${id.value}/${fileName}`)
.then((res) => {
const data = res.data.downloadUrl;
window.open(data, "_blank");
@ -127,7 +129,7 @@ function deleteFile(fileName: string) {
dialogRemove($q, async () => {
showLoader();
http
.delete(config.API.file + `/KPI/ไฟล์เอกสาร/${id.value}/${fileName}`)
.delete(config.API.kpiFile + `/KPI/ไฟล์เอกสาร/${id.value}/${fileName}`)
.then((res) => {
success($q, `ลบไฟล์สำเร็จ`);
@ -215,6 +217,7 @@ onMounted(() => {
>
<q-btn
v-if="!isReadonly"
size="12px"
flat
round

View file

@ -1,4 +1,4 @@
<script setup lang="ts">
<!-- <script setup lang="ts">
import { ref, reactive, onMounted, watch } from "vue";
import DialogHeader from "@/components/DialogHeader.vue";
import type { DataOptions } from "@/modules/08_KPI/interface/index/Main";
@ -169,7 +169,7 @@ function onSubmit() {
function getData() {
showLoader();
http
.get(config.API.KpiCapacity + `?type=${type.value}`)
.get(config.API.kpiCapacity + `?type=${type.value}`)
.then((res) => {
const data = res.data.result.data;
listTarget.value = data;
@ -428,8 +428,8 @@ watch(
</div>
<div
v-if="dataListCapacityDetails.length == 0"
class="q-pa-md text-weight-bold col-12 text-center "
style="border: 2px solid #f5f5f5;"
class="q-pa-md text-weight-bold col-12 text-center"
style="border: 2px solid #f5f5f5"
>
<span>ไมพบขอมลสมรรถนะ</span>
</div>
@ -483,4 +483,4 @@ watch(
border: 1px solid #ededed !important;
border-radius: 8px;
}
</style>
</style> -->

View file

@ -77,9 +77,9 @@ const splitterModel = ref<number>(12);
class="q-pa-none"
>
<Assessment v-if="store.tabMain === '1'" />
<Evaluator v-if="store.tabMain === '2'" />
<CommanderAbove v-if="store.tabMain === '3'" />
<CommanderAboveOneStep v-if="store.tabMain === '4'" />
<Evaluator v-if="store.tabMain === '2'" :type="'evaluator'" />
<Evaluator v-if="store.tabMain === '3'" :type="'commander'" />
<Evaluator v-if="store.tabMain === '4'" :type="'commanderHigh'" />
<File v-if="store.tabMain === '5'" />
</q-tab-panel>
</q-tab-panels>

View file

@ -26,4 +26,18 @@ interface capacityDetails {
level: string;
}
export type { ResRound, ResDataCapacity };
interface ResEvaluator {
createdAt: string;
createdFullName: string;
createdUserId: string;
id: string;
kpiUserEvaluationId: string;
lastUpdateFullName: string;
lastUpdateUserId: string;
lastUpdatedAt: string;
reason: string;
topic: string;
type: string;
}
export type { ResRound, ResDataCapacity, ResEvaluator };

View file

@ -4,7 +4,7 @@ import type { DataOption } from "@/modules/14_KPI/interface/index/Main";
// store
export const useKPIDataStore = defineStore("KPIDataStore", () => {
// const competencyType = ref<string>("HEAD");
const competencyTypeVal = ref<string>("HEAD");
const tabMain = ref<string>("1");
const dataProfile = ref<any>();
@ -175,6 +175,7 @@ export const useKPIDataStore = defineStore("KPIDataStore", () => {
}
return {
competencyTypeVal,
competencyType,
convertStatus,
convertResults,

View file

@ -20,7 +20,7 @@ const { showLoader, hideLoader, messageError, date2Thai, dialogConfirm } =
const filterKeyword = ref<string>("");
const rows = ref<any>();
const rows = ref<any[]>([]);
const year = ref<number>(new Date().getFullYear());
@ -125,7 +125,7 @@ function fetchList() {
http
.get(
config.API.kpiUserEvaluation +
`/admin?page=${formQuery.page}&pageSize=${formQuery.pageSize}&kpiPeriodId=${round.value}`
`/admin?page=${formQuery.page}&pageSize=${formQuery.pageSize}&kpiPeriodId=${round.value}&keyword=${filterKeyword.value}`
)
.then((res) => {
const data = res.data.result;
@ -243,7 +243,7 @@ onMounted(async () => {
outlined
dense
v-model="filterKeyword"
label="ค้นหา"
label="ค้นหาชื่อผู้ขอรับการประเมิน"
@keydown.enter.prevent="changRound"
>
<template v-slot:append>

View file

@ -185,7 +185,7 @@ const visibleColumns = ref<string[]>([
"commandNumber",
"commandDate",
]);
const files = ref<any>([]);
const files = ref<any>(null);
const pagination = ref({
page: 1,
rowsPerPage: 10,
@ -254,6 +254,7 @@ function sendRecordRegistry() {
.get(config.API.developmentMainTab("tab6/done", id.value))
.then((res) => {
success($q, "ส่งข้อมูลสำเร็จ");
getData();
})
.catch((e) => {
messageError($q, e);