Merge branch 'develop' into devTee
This commit is contained in:
commit
c25f0e1efd
11 changed files with 232 additions and 55 deletions
|
|
@ -105,8 +105,7 @@ const itemsMenu = computed(() => {
|
|||
if (
|
||||
leaveReason.value ===
|
||||
"(พ้นจากราชการด้วยสาเหตุ: ได้รับโทษทางวินัย ให้ออกจากราชการไว้ก่อน)" ||
|
||||
leaveReason.value ===
|
||||
"(พ้นจากราชการด้วยสาเหตุ: ลาออกจากราชการ)"
|
||||
leaveReason.value === "(พ้นจากราชการด้วยสาเหตุ: ลาออกจากราชการ)"
|
||||
) {
|
||||
return (
|
||||
baseItemsMenu.value?.filter(
|
||||
|
|
@ -140,7 +139,7 @@ const activeImage = ref<any | null>(null);
|
|||
const images = ref<any[]>([]);
|
||||
const imagesAlldata = ref<any[]>([]);
|
||||
input.type = "file";
|
||||
input.accept = ".jpg,.png,.tif,.pic";
|
||||
input.accept = ".jpg,.png,.tif,.pic,.jfif";
|
||||
|
||||
input.addEventListener("change", (e) => {
|
||||
profileFile.value = (e.currentTarget as HTMLInputElement).files?.[0];
|
||||
|
|
@ -156,31 +155,96 @@ function imageActive(n: any) {
|
|||
activeImage.value = n;
|
||||
}
|
||||
|
||||
// ฟังก์ชันสำหรับปรับขนาดภาพ
|
||||
function resizeImage(file: File): Promise<File> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image();
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = (e) => {
|
||||
img.src = e.target!.result as string; // แปลงเป็น string
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
const width = 150;
|
||||
const height = 200;
|
||||
|
||||
// ปรับขนาดภาพ
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
if (ctx) {
|
||||
// ตั้งค่าสีพื้นหลังเป็นสีขาว
|
||||
ctx.fillStyle = "white";
|
||||
ctx.fillRect(0, 0, width, height); // วาดสี่เหลี่ยมสีขาวที่เต็ม canvas
|
||||
|
||||
// ตรวจสอบว่า ctx ไม่เป็น null
|
||||
const imgAspectRatio = img.width / img.height;
|
||||
const targetAspectRatio = width / height;
|
||||
|
||||
let drawWidth: number, drawHeight: number;
|
||||
|
||||
if (imgAspectRatio > targetAspectRatio) {
|
||||
drawWidth = width;
|
||||
drawHeight = width / imgAspectRatio;
|
||||
} else {
|
||||
drawHeight = height;
|
||||
drawWidth = height * imgAspectRatio;
|
||||
}
|
||||
|
||||
const xOffset = (width - drawWidth) / 2;
|
||||
const yOffset = (height - drawHeight) / 2;
|
||||
|
||||
ctx.drawImage(img, xOffset, yOffset, drawWidth, drawHeight);
|
||||
|
||||
// แปลง canvas เป็น Blob
|
||||
canvas.toBlob((blob) => {
|
||||
if (blob) {
|
||||
resolve(new File([blob], file.name, { type: file.type })); // สร้าง File ใหม่จาก Blob
|
||||
} else {
|
||||
reject(new Error("Failed to convert canvas to blob."));
|
||||
}
|
||||
}, "image/jpeg");
|
||||
} else {
|
||||
reject(new Error("Failed to get canvas context."));
|
||||
}
|
||||
};
|
||||
img.onerror = (err) => reject(err);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
const newProfileFile = ref<any>(null);
|
||||
|
||||
/**
|
||||
* ฟังก์ชันอัปโหลด
|
||||
*/
|
||||
function uploadImg() {
|
||||
async function uploadImg() {
|
||||
showLoader();
|
||||
newProfileFile.value = await resizeImage(profileFile.value);
|
||||
closeImage();
|
||||
http
|
||||
.post(config.API.orgProfileAvatarbyType(empType.value), {
|
||||
profileId: empType.value == "" ? profileId.value : undefined,
|
||||
profileEmployeeId: empType.value !== "" ? profileId.value : undefined,
|
||||
})
|
||||
.then((res) => {
|
||||
.then(async (res) => {
|
||||
fileName.value = res.data.result.avatarName;
|
||||
uploadProfile(res.data.result.avatar);
|
||||
await uploadProfile(res.data.result.avatar);
|
||||
})
|
||||
.catch((e) => {
|
||||
messageError($q, e);
|
||||
})
|
||||
.finally(() => {});
|
||||
hideLoader();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ฟังก์ชันสร้าง path อัปโหลไฟล์
|
||||
* @param path
|
||||
*/
|
||||
function uploadProfile(path: string) {
|
||||
http
|
||||
async function uploadProfile(path: string) {
|
||||
await http
|
||||
.post(config.API.fileByPath(path), {
|
||||
replace: true,
|
||||
fileList: [
|
||||
|
|
@ -189,15 +253,12 @@ function uploadProfile(path: string) {
|
|||
},
|
||||
],
|
||||
})
|
||||
.then((res) => {
|
||||
.then(async (res) => {
|
||||
uploadUrl.value = res.data[fileName.value].uploadUrl;
|
||||
uploadFileURL(uploadUrl.value, profileFile.value);
|
||||
closeImage();
|
||||
await uploadFileURL(uploadUrl.value, newProfileFile.value);
|
||||
})
|
||||
.catch((err) => {
|
||||
messageError($q, err);
|
||||
})
|
||||
.finally(() => {
|
||||
hideLoader();
|
||||
});
|
||||
}
|
||||
|
|
@ -207,7 +268,7 @@ function uploadProfile(path: string) {
|
|||
* @param uploadUrl path อัปโหลไฟล์
|
||||
* @param file ไฟล์
|
||||
*/
|
||||
function uploadFileURL(uploadUrl: string, file: any) {
|
||||
async function uploadFileURL(uploadUrl: string, file: any) {
|
||||
showLoader();
|
||||
axios
|
||||
.put(uploadUrl, file, {
|
||||
|
|
@ -215,8 +276,8 @@ function uploadFileURL(uploadUrl: string, file: any) {
|
|||
"Content-Type": file.type,
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
fetchProfile(profileId.value);
|
||||
.then(async () => {
|
||||
await fetchProfile(profileId.value);
|
||||
success($q, "อัปโหลดไฟล์สำเร็จ");
|
||||
})
|
||||
.catch((err) => {
|
||||
|
|
@ -231,8 +292,8 @@ function uploadFileURL(uploadUrl: string, file: any) {
|
|||
* ฟังก์ชันดึงข้อมูลรูปโปรไฟล์
|
||||
* @param id โปรไฟล์
|
||||
*/
|
||||
function fetchProfile(id: string) {
|
||||
http
|
||||
async function fetchProfile(id: string) {
|
||||
await http
|
||||
.get(config.API.fileByFile("ทะเบียนประวัติ", "โปรไฟล์", id, fileName.value))
|
||||
.then(async (res) => {
|
||||
profilePicture.value = res.data.downloadUrl;
|
||||
|
|
@ -1028,7 +1089,7 @@ onMounted(async () => {
|
|||
<!-- Dialog เลือก Image -->
|
||||
<q-dialog v-model="dialogImage" persistent>
|
||||
<q-card style="width: 100vw; max-width: 60vw">
|
||||
<DialogHeader :tittle="'เลือกรูปภาพ'" :close="closeImage" />
|
||||
<DialogHeader :tittle="'เลือกรูปภาพ (150 x 200 px)'" :close="closeImage" />
|
||||
|
||||
<q-separator />
|
||||
<q-card-section class="col-12 row">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted, ref } from "vue";
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import { useQuasar } from "quasar";
|
||||
|
||||
import { useSalaryListSDataStore } from "@/modules/13_salary/store/SalaryListsStore";
|
||||
|
|
@ -55,6 +55,15 @@ const lastPage = ref<number>(0);
|
|||
const modalCommand = ref<boolean>(false);
|
||||
const isOfficer = ref<boolean>(false);
|
||||
const isStaff = ref<boolean>(false);
|
||||
const titleCommand = computed(() => {
|
||||
return `ปีงบประมาณ ${year.value + 543} รอบการขึ้นเงินเดือน ${
|
||||
roundFilter.value?.shortCode === "SPECIAL"
|
||||
? roundFilter.value?.name
|
||||
? roundFilter.value?.name
|
||||
: ""
|
||||
: `1 ${roundFilter.value?.name ? roundFilter.value?.name : ""}`
|
||||
} `;
|
||||
});
|
||||
|
||||
/**
|
||||
* function เรียกข้อมูลรอบการขึ้นเงินเดือน
|
||||
|
|
@ -246,7 +255,6 @@ async function fetchSalalyPeriod(
|
|||
.post(config.API.salaryListPeriodLatest, body)
|
||||
.then(async (res) => {
|
||||
const data = await res.data.result;
|
||||
console.log(data);
|
||||
|
||||
if (roundFilter.value.shortCode !== "SPECIAL") {
|
||||
if (Object.values(data).includes(null)) {
|
||||
|
|
@ -464,7 +472,7 @@ onMounted(async () => {
|
|||
<q-select
|
||||
v-if="roundFilter ? roundFilter.shortCode !== 'SPECIAL' : false"
|
||||
v-model="snapFilter"
|
||||
label="รอบ"
|
||||
label="ราชชื่อรอบ"
|
||||
dense
|
||||
outlined
|
||||
emit-value
|
||||
|
|
@ -565,6 +573,7 @@ onMounted(async () => {
|
|||
system-name="SALARY"
|
||||
:command-type-code-array="['C-PM-33', 'C-PM-34', 'C-PM-35']"
|
||||
:salary-period-id="salaryPeriodId"
|
||||
:title-command="titleCommand"
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted, ref, nextTick } from "vue";
|
||||
import { onMounted, ref, nextTick, computed } from "vue";
|
||||
import { useQuasar } from "quasar";
|
||||
|
||||
import { useSalaryEmployeeListSDataStore } from "@/modules/13_salary/store/SalaryEmployeeListsStore";
|
||||
|
|
@ -57,6 +57,15 @@ const nextPage = ref<number>(1);
|
|||
const modalCommand = ref<boolean>(false);
|
||||
const isOfficer = ref<boolean>(false);
|
||||
const isStaff = ref<boolean>(false);
|
||||
const titleCommand = computed(() => {
|
||||
return `ปีงบประมาณ ${year.value + 543} รอบการขึ้นเงินเดือน ${
|
||||
roundFilter.value?.shortCode === "SPECIAL"
|
||||
? roundFilter.value?.name
|
||||
? roundFilter.value?.name
|
||||
: ""
|
||||
: `1 ${roundFilter.value?.name ? roundFilter.value?.name : ""}`
|
||||
} `;
|
||||
});
|
||||
|
||||
/**
|
||||
* function เรียกข้อมูลรอบการขึ้นค่าจ้าง
|
||||
|
|
@ -463,7 +472,7 @@ onMounted(async () => {
|
|||
<q-select
|
||||
v-if="roundFilter ? roundFilter.shortCode !== 'SPECIAL' : false"
|
||||
v-model="snapFilter"
|
||||
label="รอบ"
|
||||
label="ราชชื่อรอบ"
|
||||
dense
|
||||
outlined
|
||||
emit-value
|
||||
|
|
@ -557,6 +566,7 @@ onMounted(async () => {
|
|||
system-name="SALARY_EMP"
|
||||
:command-type-code-array="['C-PM-36', 'C-PM-37']"
|
||||
:salary-period-id="salaryPeriodId"
|
||||
:title-command="titleCommand"
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ const props = defineProps({
|
|||
systemName: String, // ไอดีประเภทคำสั่ง
|
||||
orgPublishDate: { type: Date || undefined, defult: undefined },
|
||||
salaryPeriodId: { type: String, defult: "" }, // รอบเงินเดือน
|
||||
titleCommand: { type: String, defult: "" },
|
||||
});
|
||||
|
||||
const commandOp = ref<ListCommand[]>([]); // ประเภทคำสั่ง
|
||||
|
|
@ -281,7 +282,14 @@ watch(modal, async () => {
|
|||
<q-dialog v-model="modal" persistent>
|
||||
<q-card style="min-width: 50vw">
|
||||
<q-form greedy @submit.prevent @validation-success="onSubmit">
|
||||
<DialogHeader :tittle="'สร้างคำสั่ง'" :close="closeModal" />
|
||||
<DialogHeader
|
||||
:tittle="`สร้างคำสั่ง ${
|
||||
props.systemName === 'SALARY' || props.systemName === 'SALARY_EMP'
|
||||
? props.titleCommand
|
||||
: ''
|
||||
}`"
|
||||
:close="closeModal"
|
||||
/>
|
||||
<q-separator />
|
||||
<q-card-section style="max-height: 50vh" class="scroll">
|
||||
<div class="row q-sm q-col-gutter-sm">
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
import { reactive } from "vue";
|
||||
import { reactive, watch } from "vue";
|
||||
import { useQuasar } from "quasar";
|
||||
|
||||
import { useCounterMixin } from "@/stores/mixin";
|
||||
import config from "@/app.config";
|
||||
import http from "@/plugins/http";
|
||||
|
||||
import type { PropType } from "vue";
|
||||
import type { DataPositionCondition } from "@/modules/19_condition/interface/response/Main";
|
||||
import type { FormPositionCondition } from "@/modules/19_condition/interface/request/Main";
|
||||
|
||||
import DialogHeader from "@/components/DialogHeader.vue";
|
||||
|
||||
const $q = useQuasar();
|
||||
|
|
@ -15,10 +19,13 @@ const { showLoader, hideLoader, messageError, success, dialogConfirm } =
|
|||
const modal = defineModel<boolean>("modal", { required: true });
|
||||
const props = defineProps({
|
||||
fetchData: { type: Function, required: true },
|
||||
dataCondition: { type: Object, required: true },
|
||||
dataCondition: {
|
||||
type: Object as PropType<DataPositionCondition | undefined>,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const formData = reactive({
|
||||
const formData = reactive<FormPositionCondition>({
|
||||
isCondition: false,
|
||||
conditionReason: "",
|
||||
});
|
||||
|
|
@ -31,22 +38,34 @@ function onCloseDialog() {
|
|||
|
||||
function onSubmit() {
|
||||
dialogConfirm($q, async () => {
|
||||
// showLoader();
|
||||
// await http
|
||||
// .put(config.API.รอAPI, formData)
|
||||
// .then(async () => {
|
||||
// await props.fetchData?.();
|
||||
// onCloseDialog();
|
||||
// success($q, "บันทึกข้อมูลสำเร็จ");
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// messageError($q, err);
|
||||
// })
|
||||
// .finally(() => {
|
||||
// hideLoader();
|
||||
// });
|
||||
showLoader();
|
||||
await http
|
||||
.put(
|
||||
config.API.positionCondition + `/${props?.dataCondition?.id}`,
|
||||
formData
|
||||
)
|
||||
.then(async () => {
|
||||
await props.fetchData?.();
|
||||
onCloseDialog();
|
||||
success($q, "บันทึกข้อมูลสำเร็จ");
|
||||
})
|
||||
.catch((err) => {
|
||||
messageError($q, err);
|
||||
})
|
||||
.finally(() => {
|
||||
hideLoader();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
watch(modal, () => {
|
||||
if (modal.value) {
|
||||
if (props.dataCondition) {
|
||||
formData.isCondition = props.dataCondition.isCondition;
|
||||
formData.conditionReason = props.dataCondition.conditionReason;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -77,6 +96,7 @@ function onSubmit() {
|
|||
v-model="formData.conditionReason"
|
||||
label="หมายเหตุ"
|
||||
type="textarea"
|
||||
class="inputgreen"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
5
src/modules/19_condition/interface/index/Main.ts
Normal file
5
src/modules/19_condition/interface/index/Main.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
interface Pagination {
|
||||
rowsPerPage: number;
|
||||
}
|
||||
|
||||
export type { Pagination };
|
||||
5
src/modules/19_condition/interface/request/Main.ts
Normal file
5
src/modules/19_condition/interface/request/Main.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
interface FormPositionCondition {
|
||||
isCondition: boolean;
|
||||
conditionReason: string;
|
||||
}
|
||||
export type { FormPositionCondition };
|
||||
45
src/modules/19_condition/interface/response/Main.ts
Normal file
45
src/modules/19_condition/interface/response/Main.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
interface OrgTree {
|
||||
orgTreeId: string;
|
||||
orgRootId: string;
|
||||
orgLevel: number;
|
||||
orgTreeName: string;
|
||||
orgTreeShortName: string;
|
||||
orgTreeCode: string;
|
||||
orgCode: string;
|
||||
orgTreeRank: string;
|
||||
orgTreeOrder: number | null;
|
||||
orgRootCode: string;
|
||||
orgTreePhoneEx: string;
|
||||
orgTreePhoneIn: string;
|
||||
orgTreeFax: string;
|
||||
orgRevisionId: string;
|
||||
isOfficer: boolean;
|
||||
children: OrgTree[];
|
||||
}
|
||||
|
||||
interface DataPositionCondition {
|
||||
conditionReason: string;
|
||||
id: string;
|
||||
isCondition: boolean;
|
||||
orgShortname: string;
|
||||
posMasterNo: number;
|
||||
posMasterNoPrefix: string | null;
|
||||
posMasterNoSuffix: string | null;
|
||||
profilePosition: string;
|
||||
profilePoslevel: string;
|
||||
profilePostype: string;
|
||||
positions: Positions[];
|
||||
}
|
||||
|
||||
interface Positions {
|
||||
id: string;
|
||||
posExecutiveName: string;
|
||||
posLevelName: string;
|
||||
posTypeName: string;
|
||||
positionArea: string;
|
||||
positionExecutiveField: string;
|
||||
positionField: string;
|
||||
positionName: string;
|
||||
}
|
||||
|
||||
export type { OrgTree, DataPositionCondition };
|
||||
|
|
@ -7,6 +7,11 @@ import http from "@/plugins/http";
|
|||
import config from "@/app.config";
|
||||
|
||||
import type { QTableProps } from "quasar";
|
||||
import type {
|
||||
OrgTree,
|
||||
DataPositionCondition,
|
||||
} from "@/modules/19_condition/interface/response/Main";
|
||||
import type { Pagination } from "@/modules/19_condition/interface/index/Main";
|
||||
|
||||
import LoadView from "@/components/LoadView.vue";
|
||||
import DialogCondition from "@/modules/19_condition/components/DialogCondition.vue";
|
||||
|
|
@ -20,7 +25,7 @@ const isLoadTable = ref<boolean>(false);
|
|||
const activeId = ref<string>("");
|
||||
const filter = ref<string>("");
|
||||
const orgTreeId = ref<string>("");
|
||||
const nodeTree = ref<any[]>([]);
|
||||
const nodeTree = ref<OrgTree[]>([]);
|
||||
const expanded = ref<string[]>([]);
|
||||
|
||||
//Table
|
||||
|
|
@ -32,9 +37,9 @@ const orgLevel = ref<number>(0);
|
|||
const totalPage = ref<number>(1);
|
||||
const totalRow = ref<number>(0);
|
||||
const modalCondition = ref<boolean>(false);
|
||||
const dataCondition = ref<any>();
|
||||
const dataCondition = ref<DataPositionCondition>();
|
||||
|
||||
const rows = ref<any[]>([]);
|
||||
const rows = ref<DataPositionCondition[]>([]);
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
rowsPerPage: 10,
|
||||
|
|
@ -230,7 +235,7 @@ async function fetchDataTree(id: string) {
|
|||
});
|
||||
}
|
||||
|
||||
function onSelectedOrgTree(data: any) {
|
||||
function onSelectedOrgTree(data: OrgTree) {
|
||||
orgTreeId.value = data.orgTreeId;
|
||||
orgLevel.value = data.orgLevel;
|
||||
fetchDataTable();
|
||||
|
|
@ -243,7 +248,7 @@ async function fetchDataTable() {
|
|||
rows.value = [];
|
||||
isLoadTable.value = true;
|
||||
await http
|
||||
.post(config.API.orgPosMasterList, {
|
||||
.post(config.API.positionCondition, {
|
||||
id: orgTreeId.value,
|
||||
type: orgLevel.value,
|
||||
isAll: isAll.value,
|
||||
|
|
@ -256,7 +261,8 @@ async function fetchDataTable() {
|
|||
const data = await res.data.result;
|
||||
totalRow.value = data.total;
|
||||
totalPage.value = Math.ceil(data.total / pageSize.value);
|
||||
rows.value = data.data.map((e: any) => ({
|
||||
|
||||
rows.value = data.data.map((e: DataPositionCondition) => ({
|
||||
...e,
|
||||
profilePosition: e.profilePosition
|
||||
? e.profilePosition
|
||||
|
|
@ -282,12 +288,11 @@ function onSearchDataTable() {
|
|||
fetchDataTable();
|
||||
}
|
||||
|
||||
function updatePagination(newPagination: any) {
|
||||
function updatePagination(newPagination: Pagination) {
|
||||
pageSize.value = newPagination.rowsPerPage;
|
||||
}
|
||||
|
||||
function onSetCondution(data: any) {
|
||||
console.log(data);
|
||||
function onSetCondution(data: DataPositionCondition) {
|
||||
dataCondition.value = data;
|
||||
modalCondition.value = true;
|
||||
}
|
||||
|
|
@ -450,7 +455,13 @@ onMounted(async () => {
|
|||
:props="props"
|
||||
>
|
||||
<div v-if="col.name === 'isCondition'">
|
||||
<q-icon name="check" color="primary" />
|
||||
<q-icon
|
||||
v-if="col.value"
|
||||
name="check"
|
||||
color="primary"
|
||||
size="sm"
|
||||
/>
|
||||
<span v-else>-</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
{{ col.value ? col.value : "-" }}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue