Merge branch 'develop' into devTee

This commit is contained in:
setthawutttty 2025-03-04 13:59:08 +07:00
commit 6fea0f1851
14 changed files with 282 additions and 81 deletions

View file

@ -18,6 +18,7 @@ import type {
ResListSalary,
ResType,
} from "@/modules/04_registryPerson/interface/response/Salary";
import type { DataCardPos } from "@/modules/04_registryPerson/interface/index/government";
import DialogHeader from "@/components/DialogHeader.vue";
import DialogHistory from "@/modules/04_registryPerson/components/detail/GovernmentInformation/07_PositionHistory.vue";
@ -47,6 +48,7 @@ const {
success,
pathRegistryEmp,
onSearchDataTable,
formatDatePosition,
} = useCounterMixin();
const empType = ref<string>(pathRegistryEmp(route.name?.toString() ?? ""));
@ -289,30 +291,23 @@ const posExecutiveOptionMain = ref<DataOption[]>([]);
const docOption = ref<DataOption2[]>(store.optionTemplateDoc);
const cardData = ref<any[]>([
const cardData = ref<DataCardPos[]>([
{
label: "ระยะเวลาดำรงตำแหน่งในสายงาน",
data: [
{ name: "ตำแหน่ง", time: "1 ปี" },
{ name: "ตำแหน่ง", time: "1 ปี" },
{ name: "ตำแหน่ง", time: "1 ปี" },
{ name: "ตำแหน่ง", time: "1 ปี" },
{ name: "ตำแหน่ง", time: "1 ปี" },
],
data: [],
},
{
label: "ระยะเวลาดำรงตำแหน่งตามระดับ",
data: [{ name: "ละดับ", time: "1 ปี" }],
data: [],
},
{
label: "ระยะเวลาดำรงตำแหน่งทางการบริหาร",
data: [{ name: "ตำแหน่งทางการบริหาร", time: "1 ปี" }],
data: [],
},
]);
/** function fetch รายการ ตำแหน่งเงินเดือน*/
async function fetchListSalary() {
showLoader();
await http
.get(
config.API.profileListSalaryPositionNew(profileId.value, empType.value)
@ -323,9 +318,6 @@ async function fetchListSalary() {
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
@ -558,13 +550,13 @@ function onSubmit() {
: config.API.profileSalaryPositionNew(empType.value);
const method = isStatusEdit.value ? "patch" : "post";
await http[method](url, formData);
await onClickCloseDialog();
await fetchListSalary();
await onClickCloseDialog();
success($q, "บันทึกข้อมูลสำเร็จ");
} catch (e) {
messageError($q, e);
hideLoader();
} finally {
hideLoader();
}
});
}
@ -731,14 +723,56 @@ function serchDataTable() {
);
}
async function fetchDataTenure() {
await http
.get(config.API.salaryTenurePosition(profileId.value, empType.value))
.then((res) => {
const data = res.data.result;
if (data) {
// map
const formatData = (list: any) =>
list.map((e: any) => ({
name: e.name ?? "",
time: formatDatePosition(e.year, e.month, e.day),
}));
// data
const position = formatData(data.position); //
const posLevel = formatData(data.posLevel); //
const posExecutive = formatData(data.posExecutive); //
// cardData
cardData.value[0].data = position;
cardData.value[1].data = posLevel;
cardData.value[2].data = posExecutive;
// cardData
if (posExecutive.length === 0) {
cardData.value.splice(2, 2);
}
}
})
.catch((err) => {
messageError($q, err);
});
}
/** ทำงานเมื่อ Components ถูกเรียกใช้งาน*/
onMounted(() => {
fetchListSalary();
onMounted(async () => {
try {
showLoader();
await Promise.all([
fetchListSalary(),
empType.value === "" ? fetchDataTenure() : Promise.resolve(),
]);
} finally {
hideLoader();
}
});
</script>
<template>
<div class="row q-col-gutter-sm q-pb-sm">
<div class="row q-col-gutter-sm q-pb-sm" v-if="empType === ''">
<div class="col" v-for="(item, index) in cardData" :key="index">
<q-card bordered class="col-12" style="border: 1px solid #d6dee1">
<div class="col-12 text-weight-medium bg-grey-1 q-py-xs q-px-md">
@ -746,9 +780,7 @@ onMounted(() => {
</div>
<div class="col-12"><q-separator /></div>
<q-card-section class="q-pt-none" style="min-height: 200px">
<li v-for="data in item.data" :key="data.id">
{{ data.name }} {{ data.time }}
</li>
<li v-for="data in item.data">{{ data.name }} {{ data.time }}</li>
</q-card-section>
</q-card>
</div>

View file

@ -128,7 +128,9 @@ const columns = ref<QTableProps["columns"]>([
style: "font-size: 14px",
format: (v) => (v === true ? "ใช่" : "ไม่ใช่"),
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
a
.toString()
.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "degree",
@ -139,7 +141,9 @@ const columns = ref<QTableProps["columns"]>([
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
a
.toString()
.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "field",
@ -891,7 +895,6 @@ onMounted(async () => {
class="custom-header-table"
:visible-columns="visibleColumns"
v-model:pagination="pagination"
>
<template v-slot:header="props">
<q-tr :props="props">

View file

@ -921,6 +921,7 @@ onMounted(() => {
dense
class="custom-header-table"
:visible-columns="historyVisibleColumns"
v-model:pagination="historyPagination"
>
<template v-slot:header="props">
<q-tr :props="props">

View file

@ -47,4 +47,14 @@ interface RequestItemsHistoryObject {
createdFullName: string | null;
createdAt: Date;
}
export type { RequestItemsHistoryObject, FormMain };
interface DataCardPos {
label: string;
data?: Data[];
}
interface Data {
name: string;
time: string;
}
export type { RequestItemsHistoryObject, FormMain, DataCardPos };

View file

@ -13,7 +13,7 @@ import http from "@/plugins/http";
import config from "@/app.config";
import { useRegistryNewDataStore } from "@/modules/04_registryPerson/store";
import { useCounterMixin } from "@/stores/mixin";
import { useRoute } from "vue-router";
import { useRoute, useRouter } from "vue-router";
import avatar from "@/assets/avatar_user.jpg";
import { useStructureTree } from "@/stores/structureTree";
@ -40,6 +40,7 @@ const store = useRegistryNewDataStore();
const { fetchStructureTree } = useStructureTree();
const { showLoader, hideLoader, messageError } = useCounterMixin();
const route = useRoute();
const router = useRouter();
const empType = ref<string>("officer"); // officer / employee / perm
const dataPersonMain = ref<DataPerson[]>([]); //
@ -391,6 +392,10 @@ function getSearch() {
fetchDataPerson();
}
function goToAdvancedSearch() {
router.push("/report/registry");
}
/** hook เมื่อมีการเรียกใช้ Components*/
onMounted(async () => {
await Promise.all([selectType(), fetchTree()]);
@ -596,12 +601,23 @@ onMounted(async () => {
<q-space />
<div class="q-pt-sm q-pr-sm">
<a href="/report/registry" class="text-white">
<!-- <a href="/report/registry" class="text-white">
การคนหาขนส
<q-tooltip
>ไปยงหนาการคนหาขนส (Advanced search)</q-tooltip
>
</a>
</a> -->
<q-btn
flat
@click="goToAdvancedSearch"
class="text-white"
style="text-decoration: underline"
label="การค้นหาขั้นสูง"
>
<q-tooltip
>ไปยงหนาการคนหาขนส (Advanced search)</q-tooltip
>
</q-btn>
</div>
<q-separator

View file

@ -315,6 +315,7 @@ onMounted(() => {
>
กษาการในตำแหน
<q-space />
<q-btn
class="q-px-sm"
v-if="storeActing.isOfficer"
@ -332,7 +333,7 @@ onMounted(() => {
<q-card style="height: 100%">
<q-card-section :horizontal="$q.screen.gt.sm">
<!-- โครงสราง -->
<q-card-section class="col-lg-3 col-md-4 col-xs-12 q-gutter-sm">
<q-card-section class="col-lg-3 col-md-4 col-xs-12 q-gutter-sm q-pa-sm">
<div>
<q-input dense outlined v-model="filter" label="ค้นหา">
<template v-slot:append>
@ -671,7 +672,7 @@ onMounted(() => {
/>
</template>
<style scoped>
<style lang="scss" scoped>
.tree-container {
overflow: auto;
height: 74vh;

View file

@ -1,5 +1,15 @@
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { useQuasar } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin";
import type { DataCardPos } from "@/modules/04_registryPerson/interface/index/government";
const $q = useQuasar();
const { messageError, formatDatePosition } = useCounterMixin();
/** props*/
const props = defineProps({
@ -11,30 +21,64 @@ const props = defineProps({
type: { type: String, default: "" },
});
const cardData = ref<any[]>([
const cardData = ref<DataCardPos[]>([
{
label: "ระยะเวลาดำรงตำแหน่งในสายงาน",
data: [
{ name: "ตำแหน่ง", time: "1 ปี" },
{ name: "ตำแหน่ง", time: "1 ปี" },
{ name: "ตำแหน่ง", time: "1 ปี" },
{ name: "ตำแหน่ง", time: "1 ปี" },
{ name: "ตำแหน่ง", time: "1 ปี" },
],
data: [],
},
{
label: "ระยะเวลาดำรงตำแหน่งตามระดับ",
data: [{ name: "ละดับ", time: "1 ปี" }],
data: [],
},
{
label: "ระยะเวลาดำรงตำแหน่งทางการบริหาร",
data: [{ name: "ตำแหน่งทางการบริหาร", time: "1 ปี" }],
data: [],
},
]);
async function fetchDataTenure() {
if (props?.id) {
await http
.get(
config.API.salaryTenurePosition(
props?.id,
props.type === "officer" ? "" : "-employee"
)
)
.then((res) => {
const data = res.data.result;
if (data) {
// map
const formatData = (list: any) =>
list.map((e: any) => ({
name: e.name ?? "",
time: formatDatePosition(e.year, e.month, e.day),
}));
// data
const position = formatData(data.position);
const posLevel = formatData(data.posLevel);
const posExecutive = formatData(data.posExecutive);
// cardData
cardData.value[0].data = position; //
cardData.value[1].data = posLevel; //
cardData.value[2].data = posExecutive; //
// cardData
if (posExecutive.length === 0) {
cardData.value.splice(2, 2);
}
}
})
.catch((err) => {
messageError($q, err);
});
}
}
onMounted(() => {
console.log(props.id);
console.log(props.type);
fetchDataTenure();
});
</script>
@ -45,19 +89,19 @@ onMounted(() => {
<span class="q-ml-md">อมลตำแหน </span>
</div>
<div class="row q-pa-sm">
<q-list flat bordered class="col-12" style="border-radius: 5px;">
<q-list flat bordered class="col-12" style="border-radius: 5px">
<q-card flat v-for="(item, index) in cardData" :key="index">
<q-item>
<q-item-section>
<q-item-label class="text-grey-6">{{ item.label }}</q-item-label>
<q-item-label
><li v-for="data in item.data" :key="data.id">
><li v-for="data in item.data">
{{ data.name }} {{ data.time }}
</li>
</q-item-label>
</q-item-section>
</q-item>
<q-separator spaced v-if="index !== 2" />
<q-separator v-if="index !== 2" />
</q-card>
</q-list>
</div>

View file

@ -11,6 +11,7 @@ import { useCounterMixin } from "@/stores/mixin";
import { useReportStore } from "@/modules/21_report/store";
import { useRegistryNewDataStore } from "@/modules/04_registryPerson/store";
import { useStructureTree } from "@/stores/structureTree";
import { useMenuDataStore } from "@/stores/menuList";
import type { OptionData } from "@/modules/07_insignia/interface/index/Main";
import type {
@ -22,17 +23,23 @@ import type {
ResOptionPerson,
DataEducationLevel,
} from "@/modules/21_report/interface/Main";
import type { DataRoles } from "@/interface/response/main";
import type { DataStructureTree } from "@/interface/main";
import DialogOrg from "@/modules/21_report/components/01_org/DialogOrg.vue";
import PopupPersonal from "@/components/Dialogs/PopupPersonalNew.vue";
import LoadView from "@/components/LoadView.vue";
const $q = useQuasar();
const route = useRoute();
const storeReport = useReportStore();
const stroeRegistry = useRegistryNewDataStore();
const { fetchStructureTree } = useStructureTree();
const mixin = useCounterMixin();
const { messageError, showLoader, hideLoader, date2Thai } = mixin;
const storeMenu = useMenuDataStore();
const { messageError, showLoader, hideLoader, date2Thai, formatDatePosition } =
useCounterMixin();
const loadingBtn = ref<boolean>(false);
const total = ref<number>(0);
@ -43,7 +50,6 @@ const employeeClassOption = ref<OptionData[]>([
]);
const rows = ref<any[]>([]);
const detailReport = ref<any>();
/** ช่วงเวลา */
const dateStart = ref<Date | null>(null); //
@ -120,8 +126,8 @@ const visibleColumnsBase = ref<string[]>([
"dateAppoint",
"dateRetireLaw",
"age",
"currentPosition",
"lengthPosition",
"positionDate",
"levelDate",
]);
const columns = computed<QTableProps["columns"]>(() => {
@ -288,22 +294,22 @@ const columns = computed<QTableProps["columns"]>(() => {
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "currentPosition",
name: "positionDate",
align: "left",
label: "ระยะเวลาดำรงตำแหน่งปัจจุบัน",
sortable: true,
field: "currentPosition",
field: "positionDate",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "lengthPosition",
name: "levelDate",
align: "left",
label: "ระยะเวลาดำรงตำแหน่งในระดับปัจจุบัน",
sortable: true,
field: "lengthPosition",
field: "levelDate",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
@ -323,6 +329,7 @@ const rangeTerm = ref<RangeAge>({
min: 0,
max: 20,
});
const isLoadStructureTree = ref<boolean>(true);
function onOpenOrg() {
modalOrg.value = true;
@ -520,6 +527,9 @@ async function onSearch() {
sortBy: sortBy.value ? "dateAppoint" : "",
sort: sortBy.value ? sortBy.value : "ASC",
isRetireLaw: isRetireLaw.value,
tenureType: typeTerm.value,
tenureMin: typeTerm.value ? Number(rangeTerm.value.min) : null,
tenureMax: typeTerm.value ? Number(rangeTerm.value.max) : null,
};
showLoader();
await http
@ -549,8 +559,18 @@ async function onSearch() {
education: item.degree ?? "-",
dateAppoint: item.dateAppoint ?? "-",
age: item.age ?? "-",
currentPosition: item.currentPosition ?? "-",
lengthPosition: item.lengthPosition ?? "-",
positionDate:
formatDatePosition(
item.positionDate?.Years,
item.positionDate?.Months,
item.positionDate?.Days
) ?? "-",
levelDate:
formatDatePosition(
item.levelDate?.posExecutiveYears,
item.levelDate?.posExecutiveMonths,
item.levelDate?.posExecutiveDays
) ?? "-",
empType: employeeClass.value,
dateRetireLaw: item.dateRetireLaw ?? "-",
}));
@ -637,15 +657,35 @@ watch(
}
);
const node = ref<any[]>([]);
const node = ref<DataStructureTree[]>([]);
const filterTree = ref<string>("");
const expanded = ref<string[]>([]);
const expandedModal = ref<boolean>(false);
// const sysName = ref<bo>
async function fetchTree() {
const data = await fetchStructureTree(route.meta.Key as string, true);
if (data) {
node.value = data;
try {
if (storeMenu.permissions) {
isLoadStructureTree.value = true;
const response = storeMenu.permissions.roles ?? [];
const sysName = response
?.find(
(e: DataRoles) =>
e.authSysId === "SYS_REGISTRY_OFFICER" ||
e.authSysId === "REPORT_REGISTRY"
)
?.authSysId.toString();
const data = await fetchStructureTree(sysName ?? "REPORT_REGISTRY");
if (data) {
node.value = data;
}
}
} catch (err) {
messageError($q, err);
} finally {
isLoadStructureTree.value = false;
}
}
@ -683,7 +723,7 @@ onMounted(async () => {
getOptions(),
getExecutive(),
getDataPerson(),
getEducationLevel(),
// getEducationLevel(),
fetchTree(),
])
@ -697,6 +737,15 @@ onMounted(async () => {
}, 500);
});
});
watch(
() => storeMenu.permissions,
() => {
if (storeMenu.permissions) {
fetchTree();
}
}
);
</script>
<template>
@ -867,7 +916,10 @@ onMounted(async () => {
</template>
<q-separator />
<q-card-section>
<q-card-section v-if="isLoadStructureTree">
<LoadView />
</q-card-section>
<q-card-section v-else>
<q-input
dense
outlined
@ -885,7 +937,7 @@ onMounted(async () => {
</template>
</q-input>
<q-tree
class="tree-container q-mt-sm"
class="tree-container-report-registry q-mt-sm"
dense
:nodes="node"
node-key="orgTreeName"
@ -1600,9 +1652,9 @@ onMounted(async () => {
</div>
<div v-else-if="col.name === 'fullName'">
{{ col.value }}
<q-btn
size="sm"
v-if="checkPermission($route)?.attrIsGet"
flat
dense
icon="info"
@ -1654,9 +1706,9 @@ onMounted(async () => {
padding: 10px;
}
.tree-container {
.tree-container-report-registry {
overflow: auto;
height: 50vh;
max-height: 50vh;
}
.my-list-link {
color: rgb(118, 168, 222);