Merge branch 'develop' into devTee

This commit is contained in:
setthawutttty 2025-08-26 10:49:01 +07:00
commit d5912a0dc9
25 changed files with 225 additions and 134 deletions

View file

@ -44,6 +44,10 @@ const {
* props
*/
const reqMaster = defineModel<FilterMaster>("reqMaster", { required: true }); // qurey
const isPositionHolder = defineModel<boolean>("isPositionHolder", {
default: false,
});
const props = defineProps({
modal: Boolean,
close: Function,
@ -56,6 +60,7 @@ const props = defineProps({
shortName: { type: String, required: true },
orgShortName: { type: String, required: true },
dataTree: { type: Object, default: () => [] },
positionHolderInfo: { type: Object, default: () => ({}) },
});
const isReadonly = ref<boolean>(false); //
@ -104,9 +109,19 @@ const formPositionSelect = reactive<FormPositionSelect>({
});
//Table
const selectedPos = ref<RowDetailPositions[]>([]);
const rows = ref<RowDetailPositions[]>([]); //
const rowsPositionSelect = ref<RowDetailPositions[]>([]); //
const columns = ref<QTableProps["columns"]>([
{
name: "checkbox",
align: "center",
label: "ครองในตำแหน่ง",
sortable: false,
field: "checkbox",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "no",
align: "left",
@ -232,6 +247,15 @@ async function fetchPosition(id: string) {
// formData.isStaff = data.isStaff;
formData.positionSign = data.positionSign;
rows.value = data.positions;
const positionIsSelected = data.positions.find(
(item: any) => item.id === props.positionHolderInfo.position
);
if (positionIsSelected) {
selectedPos.value.push(positionIsSelected);
} else {
selectedPos.value = [];
}
})
.catch((err) => {
messageError($q, err);
@ -251,20 +275,36 @@ function onSubmit() {
//
if (rows.value.length == 0) {
dialogMessageNotify($q, "กรุณาเลือกตำแหน่งอย่างน้อย 1 ตำแหน่ง");
} else if (selectedPos.value.length == 0 && isPositionHolder.value) {
dialogMessageNotify($q, "กรุณาเลือกครองในตำแหน่ง");
} else {
// dialog
dialogConfirm($q, async () => {
const positionsData = rows.value.map((e: RowDetailPositions) => ({
posDictName: e.positionName, // ()
posDictField: e.positionField, //
posTypeId: e.posTypeId, //*
posLevelId: e.posLevelId, //*
posExecutiveId: e.posExecutiveId ? e.posExecutiveId : "", //
posDictExecutiveField: e.positionExecutiveField, //
posDictArea: e.positionArea, ///
isSpecial: e.isSpecial,
positionIsSelected: e.positionIsSelected,
}));
const isAddOrCopy =
props.actionType === "ADD" || props.actionType === "COPY";
const positionsData = rows.value.map(
(e: RowDetailPositions, index: number) => ({
id: !e.isNew ? e.id : null, //id
posDictName: e.positionName, // ()
posDictField: e.positionField, //
posTypeId: e.posTypeId, //*
posLevelId: e.posLevelId, //*
posExecutiveId: e.posExecutiveId ? e.posExecutiveId : "", //
posDictExecutiveField: e.positionExecutiveField, //
posDictArea: e.positionArea, ///
isSpecial: e.isSpecial,
positionIsSelected:
isPositionHolder.value && selectedPos.value[0]?.id === e.id
? true
: false,
orderNo: index,
})
);
// ID
const positionNew = isAddOrCopy
? positionsData.map(({ id, ...rest }) => rest)
: positionsData;
const body = {
posMasterNoPrefix: formData.prefixNo, //*Prefix Optional (/)
@ -280,56 +320,14 @@ function onSubmit() {
orgChild2Id: getOrgIdByLevel(2),
orgChild3Id: getOrgIdByLevel(3),
orgChild4Id: getOrgIdByLevel(4),
// orgRootId:
// props.actionType === "ADD"
// ? props.orgLevel === 0
// ? props.treeId
// : null
// : orgLevel.value === 0
// ? props.treeId
// : null, //Id
// orgChild1Id:
// props.actionType === "ADD"
// ? props.orgLevel === 1
// ? props.treeId
// : null
// : orgLevel.value === 1
// ? orgId.value
// : null,
// orgChild2Id:
// props.actionType === "ADD"
// ? props.orgLevel === 2
// ? props.treeId
// : null
// : orgLevel.value === 2
// ? orgId.value
// : null,
// orgChild3Id:
// props.actionType === "ADD"
// ? props.orgLevel === 3
// ? props.treeId
// : null
// : orgLevel.value === 3
// ? orgId.value
// : null,
// orgChild4Id:
// props.actionType === "ADD"
// ? props.orgLevel === 4
// ? props.treeId
// : null
// : orgLevel.value === 4
// ? orgId.value
// : null,
positions: positionsData,
positions: positionNew,
};
showLoader();
try {
const isAddOrCopy =
props.actionType === "ADD" || props.actionType === "COPY";
if (isAddOrCopy) {
await http.post(config.API.orgPosMaster, body);
await Promise.all([
props.fetchDataTable?.(
reqMaster.value.id,
@ -433,7 +431,8 @@ async function addPosition(data: RowDetailPositions) {
item.positionName == data.positionName &&
item.isSpecial == data.isSpecial
);
// data.id = null; // Reset id to ensure a new entry
data.isNew = true; // Mark as new entry
if (!isIdExist) {
rows.value = [...rows.value, data];
}
@ -448,6 +447,12 @@ function deleteData(id: string) {
const updatedRows = dataRow.filter(
(item: RowDetailPositions) => item.id !== id
);
// selectedPos
if (dataRow.find((item) => item.id === id)?.positionIsSelected) {
selectedPos.value = [];
}
rows.value = updatedRows;
}
@ -496,6 +501,8 @@ async function clearFormPositionSelect() {
isPosition.value = false;
// formData.isStaff = false;
formData.positionSign = "";
selectedPos.value = [];
isPositionHolder.value = false;
}
/**
@ -542,6 +549,18 @@ watch(
if (props.actionType !== "ADD" && props.rowId) {
fetchPosition(props.rowId);
}
visibleColumns.value = [
...(isPositionHolder.value ? ["checkbox"] : []),
"no",
"positionName",
"positionField",
"posTypeName",
"posLevelName",
"posExecutiveName",
"positionExecutiveField",
"positionArea",
];
}
}
);
@ -651,13 +670,15 @@ watch(
ref="table"
:columns="columns"
:rows="rows"
row-key="idcard"
row-key="id"
flat
bordered
:paging="true"
dense
class="custom-header-table"
:visible-columns="visibleColumns"
selection="single"
v-model:selected="selectedPos"
>
<template v-slot:header="props">
<q-tr :props="props">
@ -687,12 +708,21 @@ watch(
<q-tooltip>ลบขอม</q-tooltip>
</q-btn>
</q-td>
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
>
<div v-if="col.name == 'no'">
<div v-if="col.name === 'checkbox'">
<q-checkbox
keep-color
color="primary"
dense
v-model="props.selected"
/>
</div>
<div v-else-if="col.name == 'no'">
{{ props.rowIndex + 1 }}
</div>
<div v-else-if="col.name === 'posExecutiveName'">
@ -853,7 +883,9 @@ watch(
:paging="true"
dense
class="custom-header-table"
:visible-columns="visibleColumns"
:visible-columns="
visibleColumns.filter((col) => col !== 'checkbox')
"
>
<template v-slot:header="props">
<q-tr :props="props">

View file

@ -47,17 +47,17 @@ const columns = ref<QTableProps["columns"]>([
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "fullname",
align: "left",
label: "ชื่อคนครอง",
sortable: true,
field: "fullname",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
// {
// name: "fullname",
// align: "left",
// label: "",
// sortable: true,
// field: "fullname",
// headerStyle: "font-size: 14px",
// style: "font-size: 14px",
// sort: (a: string, b: string) =>
// a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
// },
{
name: "orgShortName",
align: "left",
@ -157,19 +157,14 @@ const columns = ref<QTableProps["columns"]>([
align: "left",
label: "วันที่แก้ไข",
field: "lastUpdatedAt",
sortable: true,
format(val, row) {
sortable: false,
format(val) {
return date2Thai(val);
},
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const pagination = ref({
sortBy: "lastUpdatedAt",
});
/**
* function เรยกขอมลประวตำแหน

View file

@ -45,7 +45,7 @@ const {
* props
*/
const modal = defineModel<boolean>("modal", { required: true });
const reqMaster = defineModel<FilterMaster>("reqMaster", { required: true });
let reqMaster = defineModel<FilterMaster>("reqMaster", { required: true });
const totalPage = defineModel<number>("totalPage", { required: true });
const nodeTree = defineModel<OrgTree[]>("nodeTree", { required: true });
const columns = defineModel<QTableProps[]>("columns", {});

View file

@ -330,7 +330,12 @@ function searchData() {
keyword: formData.personal, //
};
http
.post(config.API.orgSearchProfile, reqBody)
.post(
store.typeOrganizational === "draft"
? config.API.orgSearchProfile
: config.API.orgSearchCurrentProfile,
reqBody
)
.then((res) => {
totalPage.value = Math.ceil(res.data.result.total / pageSize.value);
const list = res.data.result.data.map((e: SelectPerson) => ({
@ -450,7 +455,7 @@ watch(
<template>
<q-dialog v-model="modal" persistent>
<q-card style="min-width: 80vw">
<form @submit.prevent="validateForm">
<q-form greedy @submit.prevent @validation-success="validateForm">
<DialogHeader :tittle="`เลือกคนครอง`" :close="close" />
<q-separator />
@ -564,6 +569,7 @@ watch(
label="ค้นหาจากชื่อ-นามสกุล หรือเลขประจำตัวประชาชน"
lazy-rules
hide-bottom-space
@keydown.enter.prevent="searchData"
/>
</div>
<div class="col-2">
@ -577,6 +583,7 @@ watch(
label="ตำแหน่งในสายงาน"
lazy-rules
hide-bottom-space
@keydown.enter.prevent="searchData"
/>
</div>
<div class="col-2">
@ -650,7 +657,6 @@ watch(
map-options
:options="columnsResult"
option-value="name"
style="min-width: 140px"
class="col-xs-12 col-sm-3 col-md-2"
/>
@ -746,7 +752,7 @@ watch(
<q-card-actions align="right" class="bg-white text-teal">
<q-btn type="submit" :label="`ยืนยัน`" color="public" />
</q-card-actions>
</form>
</q-form>
</q-card>
</q-dialog>
</template>

View file

@ -112,7 +112,7 @@ const columns = ref<QTableProps["columns"]>([
},
]);
const rows = ref<PosMaster[]>([]); //
const reqMaster = reactive<FilterMaster>({
let reqMaster = reactive<FilterMaster>({
id: "",
type: 0,
isAll: false,

View file

@ -41,7 +41,7 @@ const mainTree = ref<OrgTree>();
const selected = ref<string>("");
const reqMaster = reactive<FilterMaster>({
let reqMaster = reactive<FilterMaster>({
id: "",
type: 0,
isAll: false,
@ -118,18 +118,24 @@ async function fetchDataTable(id: string, level: number, action: boolean) {
.then(async (res) => {
const dataMain: PosMaster[] = [];
totalPage.value = Math.ceil(res.data.result.total / reqMaster.pageSize);
totalData.value = res.data.result.total;
res.data.result.data.forEach((e: PosMaster) => {
const p = e.positions;
if (p.length !== 0) {
const a = p.find((el: Position) => el.positionIsSelected === true);
const { id, ...rest } = a ? a : p[0];
const test = {
...e,
...rest,
};
dataMain.push(test);
let positionData = {};
if (p?.length > 0) {
const selectedPos = p.find(
(el: Position) => el.positionIsSelected === true
);
const targetPosition = selectedPos || p[0];
const { id, ...rest } = targetPosition;
positionData = rest;
}
const newDataMain = {
...e,
...positionData,
};
dataMain.push(newDataMain);
});
posMaster.value = store.fetchPosMaster(dataMain);
})

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, watch, computed } from "vue";
import { ref, watch, computed, reactive } from "vue";
import { useQuasar } from "quasar";
import config from "@/app.config";
@ -42,7 +42,7 @@ const { showLoader, hideLoader, messageError, success, dialogRemove } =
const nodeTree = defineModel<any>("nodeTree", { required: true });
const orgLevel = defineModel<number>("orgLevel", { required: true });
const treeId = defineModel<string>("treeId", { required: true });
const reqMaster = defineModel<FilterMaster>("reqMaster", { required: true });
let reqMaster = defineModel<FilterMaster>("reqMaster", { required: true });
const totalPage = defineModel<number>("totalPage", { required: true });
const totalData = defineModel<number>("totalData", { required: true });
const posMaster = defineModel<PosMaster2[]>("posMaster", { required: true });
@ -72,7 +72,15 @@ const modalSelectPerson = ref<boolean>(false); //เลือกคนครอ
const rowId = ref<string>(""); //id
const actionType = ref<string>(""); //
const orgShortName = ref<string>(""); //
const orgRootIdMain = ref<string>(""); //Id
const isPositionHolder = ref<boolean>(false);
const positionHolderInfo = reactive({
posMaster: "",
position: "",
profileId: " ",
isSit: false,
});
/** ListMenu Table*/
const listMenu = ref<ListMenu[]>([
{
@ -125,6 +133,32 @@ const listMenu = ref<ListMenu[]>([
},
]);
/**
* Returns filtered menu items for a given row.
*/
function getMenuItems(row: any) {
if (
row.positionIsSelected != "ว่าง" &&
store.typeOrganizational === "current"
) {
return listMenu.value.filter(
(item) =>
item.type !== "DEL" &&
item.type !== "CONDITION" &&
item.type !== "INHERIT"
);
} else if (store.typeOrganizational === "current") {
return listMenu.value.filter((item) => item.type !== "INHERIT");
} else if (
row.positionIsSelected != "ว่าง" &&
store.typeOrganizational === "draft"
) {
return listMenu.value.filter((item) => item.type !== "CONDITION");
} else {
return listMenu.value;
}
}
const baseDocument = ref<DataDocument[]>([
{
name: "บัญชี 1",
@ -298,10 +332,22 @@ function onClickPosition(
id: string,
data: PosMaster2 = {} as PosMaster2
) {
actionType.value = type;
orgShortName.value = type === "EDIT" ? data?.orgShortname : "";
rowId.value = id ? id : "";
actionType.value = type;
dialogPosition.value = !dialogPosition.value;
if (type === "EDIT") {
isPositionHolder.value = data.positionIsSelected !== "ว่าง";
positionHolderInfo.posMaster = data.id || "";
positionHolderInfo.position =
data.positions.find((e) => e.positionIsSelected === true)?.id || "";
positionHolderInfo.profileId =
store.typeOrganizational === "current"
? data.current_holderId || ""
: data.next_holderId || "";
positionHolderInfo.isSit = data.isSit || false;
}
}
/**
@ -739,16 +785,7 @@ watch(
</q-item-section>
</q-item>
<q-item
v-for="(item, index) in props.row.positionIsSelected !=
'ว่าง' && store.typeOrganizational === 'current'
? listMenu.filter(
(item) =>
item.type !== 'DEL' && item.type !== 'CONDITION'
)
: props.row.positionIsSelected != 'ว่าง' &&
store.typeOrganizational === 'draft'
? listMenu.filter((item) => item.type !== 'CONDITION')
: listMenu"
v-for="(item, index) in getMenuItems(props.row)"
:key="index"
clickable
v-close-popup
@ -956,8 +993,18 @@ watch(
{{ col.value ? col.value : "-" }}
</div>
<div v-else-if="col.name === 'positionName'">
{{ col.value ? col.value : "-" }}
<q-icon
v-if="props.row.positionIsSelected"
name="check"
color="primary"
/>
</div>
<div v-else class="text-body2">
{{ col.value }}
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
@ -1003,6 +1050,8 @@ watch(
v-model:reqMaster="reqMaster"
:fetchDataTable="props.fetchDataTable"
:getSummary="getSummary"
v-model:is-position-holder="isPositionHolder"
:position-holder-info="positionHolderInfo"
/>
<!-- ดลำด -->

View file

@ -131,7 +131,7 @@ interface FormPositionSelectRef {
}
interface RowDetailPositions {
id: string;
id: string | null;
positionId: string;
positionName: string;
positionField: string;
@ -145,6 +145,7 @@ interface RowDetailPositions {
posExecutiveId: string;
isSpecial: boolean;
positionIsSelected: string;
isNew?: boolean;
}
interface DataOption2 {

View file

@ -159,6 +159,9 @@ interface PosMaster2 {
profilePoslevel: string;
profilePostype: string;
isDirector?: boolean;
current_holderId?: string;
next_holderId?: string;
isSit?: boolean;
}
interface HistoryPos {

View file

@ -462,7 +462,7 @@ onMounted(async () => {
<q-tr
:props="props"
class="cursor-pointer"
@click.stop,pervent="
@click.stop.prevent="
onRedirectToPosition(props.row.id, props.row.type)
"
>

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { onMounted, ref, computed, reactive, watch } from "vue";
import { useQuasar, QForm, is } from "quasar";
import { useQuasar, QForm } from "quasar";
import { useInsigniaDataStore } from "@/modules/07_insignia/store";
import { useCounterMixin } from "@/stores/mixin";
@ -62,9 +62,6 @@ const props = defineProps({
roundName: {
type: String,
},
requestStatus: {
type: String,
},
fecthStat: {
type: Function,
},
@ -1152,7 +1149,8 @@ onMounted(async () => {
v-if="
DataStore.isOfficer ||
(DataStore.isStaff &&
(requestStatus == 'st1' || requestStatus == 'st4') &&
(DataStore.requestStatus == 'st1' ||
DataStore.requestStatus == 'st4') &&
(checkPermission($route)?.attrIsGet ||
checkPermission($route)?.attrIsUpdate))
"
@ -1247,17 +1245,17 @@ onMounted(async () => {
</q-btn>
</q-td>
<q-td auto-width>
<!-- <q-td auto-width>
<btnDownloadFile
v-if="
props.row.insigniaSend == 'เหรียญจักรพรรดิมาลา' &&
props.row.insigniaSend == 'เหรียญจักรพรรดิมาลา (ร.จ.พ.)' &&
checkPermission($route)?.attrIsGet
"
:profileId="props.row.profileId"
:round="DataStore.roundId"
:optionRound="DataStore.optionRound"
/>
</q-td>
</q-td> -->
<q-td key="no" :props="props">
{{ props.rowIndex + 1 }}

View file

@ -109,5 +109,8 @@ function downloadFile(response: any, filename: string) {
</q-item>
</q-list>
</q-menu>
<q-tooltip>
ดาวนโหลดไฟลประวสำหรบการเสนอขอพระราชทานเหรยญจกรพรรดมาลา
</q-tooltip>
</q-btn>
</template>

View file

@ -648,7 +648,6 @@ onUnmounted(() => {
:round-id="round"
:round-name="roundName"
:fecth-insignia-by-oc="fecthInsigniaByOc"
:request-status="requestStatus"
:fecth-stat="fecthStat"
/>
</q-tab-panel>

View file

@ -722,7 +722,8 @@ onMounted(() => {
{{ `- ${row.position}`
}}{{
props.row.groupTarget === "OFFICER" &&
(row.posType && row.posLevel)
row.posType &&
row.posLevel
? ` (${
row.posType &&
(row.posType == "อำนวยการ" ||
@ -935,9 +936,6 @@ onMounted(() => {
<div v-else class="table_ellipsis">
{{ col.value ? col.value : "-" }}
</div>
<div v-else class="table_ellipsis">
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>

View file

@ -47,7 +47,7 @@ const {
* props
*/
const modal = defineModel<boolean>("modal", { required: true });
const reqMaster = defineModel<FilterMaster>("reqMaster", { required: true });
let reqMaster = defineModel<FilterMaster>("reqMaster", { required: true });
const totalPage = defineModel<number>("totalPage", { required: true });
const nodeTree = defineModel<OrgTree[]>("nodeTree", { required: true });
const columns = defineModel<QTableProps[]>("columns", {});

View file

@ -111,7 +111,7 @@ const columns = ref<QTableProps["columns"]>([
},
]);
const rows = ref<PosMaster[]>([]);
const reqMaster = reactive<FilterMaster>({
let reqMaster = reactive<FilterMaster>({
id: "",
type: 0,
isAll: false,

View file

@ -49,7 +49,7 @@ const { showLoader, hideLoader, messageError, success, dialogRemove } =
const nodeTree = defineModel<any>("nodeTree", { required: true });
const orgLevel = defineModel<number>("orgLevel", { required: true });
const treeId = defineModel<string>("treeId", { required: true });
const reqMaster = defineModel<FilterMaster>("reqMaster", { required: true });
let reqMaster = defineModel<FilterMaster>("reqMaster", { required: true });
const totalPage = defineModel<number>("totalPage", { required: true });
const totalData = defineModel<number>("totalData", { required: true });
const posMaster = defineModel<PosMaster2[]>("posMaster", { required: true });

View file

@ -39,7 +39,7 @@ const isLoadTree = ref<boolean>(false); // loadTable
const mainTree = ref<OrgTree>();
const selected = ref<string>("");
const reqMaster = reactive<FilterMaster>({
let reqMaster = reactive<FilterMaster>({
id: "",
type: 0,
isAll: false,

View file

@ -47,7 +47,7 @@ const {
* props
*/
const modal = defineModel<boolean>("modal", { required: true });
const reqMaster = defineModel<FilterMaster>("reqMaster", { required: true });
let reqMaster = defineModel<FilterMaster>("reqMaster", { required: true });
const totalPage = defineModel<number>("totalPage", { required: true });
const nodeTree = defineModel<OrgTree[]>("nodeTree", { required: true });
const columns = defineModel<QTableProps[]>("columns", {});

View file

@ -111,7 +111,7 @@ const columns = ref<QTableProps["columns"]>([
},
]);
const rows = ref<PosMaster[]>([]);
const reqMaster = reactive<FilterMaster>({
let reqMaster = reactive<FilterMaster>({
id: "",
type: 0,
isAll: false,

View file

@ -49,7 +49,7 @@ const { showLoader, hideLoader, messageError, success, dialogRemove } =
const nodeTree = defineModel<any>("nodeTree", { required: true });
const orgLevel = defineModel<number>("orgLevel", { required: true });
const treeId = defineModel<string>("treeId", { required: true });
const reqMaster = defineModel<FilterMaster>("reqMaster", { required: true });
let reqMaster = defineModel<FilterMaster>("reqMaster", { required: true });
const totalPage = defineModel<number>("totalPage", { required: true });
const totalData = defineModel<number>("totalData", { required: true });
const posMaster = defineModel<PosMaster2[]>("posMaster", { required: true });

View file

@ -39,7 +39,7 @@ const isLoadTree = ref<boolean>(false); // loadTable
const mainTree = ref<OrgTree>();
const selected = ref<string>("");
const reqMaster = reactive<FilterMaster>({
let reqMaster = reactive<FilterMaster>({
id: "",
type: 0,
isAll: false,