Commit 530c28df by pantakan konthang

pms ปริ้น pdf

parent a27b33aa
......@@ -54,6 +54,7 @@
"glob-watcher": "^6.0.0",
"hammerjs": "^2.0.8",
"helmet": "^7.0.0",
"html2pdf.js": "^0.10.3",
"keen-slider": "^6.8.5",
"leaflet": "^1.9.4",
"lightgallery": "^2.1.2",
......@@ -97,6 +98,7 @@
"@types/d3-shape": "^3.1.1",
"@types/hammerjs": "^2.0.41",
"@types/jasmine": "~4.3.4",
"@types/jspdf": "^1.3.3",
"@types/leaflet": "^1.9.3",
"@types/mousetrap": "^1.6.11",
"@types/wnumb": "^1.2.1",
......@@ -6919,6 +6921,13 @@
"integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==",
"dev": true
},
"node_modules/@types/jspdf": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@types/jspdf/-/jspdf-1.3.3.tgz",
"integrity": "sha512-DqwyAKpVuv+7DniCp2Deq1xGvfdnKSNgl9Agun2w6dFvR5UKamiv4VfYUgcypd8S9ojUyARFIlZqBrYrBMQlew==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/leaflet": {
"version": "1.9.6",
"resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.6.tgz",
......@@ -6969,6 +6978,13 @@
"integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==",
"dev": true
},
"node_modules/@types/raf": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
"integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
"license": "MIT",
"optional": true
},
"node_modules/@types/range-parser": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.5.tgz",
......@@ -7032,9 +7048,10 @@
"integrity": "sha512-6tOUG+nVHn0cJbVp25JFayS5UE6+xlbcNF9Lo9mU7U0zk3zeUShZied4YEQZjy1JBF043FSkdXw8YkUJuVtB5g=="
},
"node_modules/@types/trusted-types": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.4.tgz",
"integrity": "sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ=="
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
"license": "MIT"
},
"node_modules/@types/wnumb": {
"version": "1.2.1",
......@@ -7978,6 +7995,18 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"dev": true
},
"node_modules/atob": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
"license": "(MIT OR Apache-2.0)",
"bin": {
"atob": "bin/atob.js"
},
"engines": {
"node": ">= 4.5.0"
}
},
"node_modules/autoprefixer": {
"version": "10.4.16",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz",
......@@ -8109,6 +8138,15 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"node_modules/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
......@@ -8533,6 +8571,18 @@
"resolved": "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz",
"integrity": "sha512-BXvDkqhDNxXEjeGM8LFkSbR+jzmP/CYpCiVKYn+soB1dDldeU15EBNDkwVXndKuX35wnNUaPd0qSoQEAkmQtMw=="
},
"node_modules/btoa": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
"integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
"license": "(MIT OR Apache-2.0)",
"bin": {
"btoa": "bin/btoa.js"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/buffer": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
......@@ -8735,6 +8785,38 @@
}
]
},
"node_modules/canvg": {
"version": "3.0.11",
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz",
"integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==",
"license": "MIT",
"optional": true,
"dependencies": {
"@babel/runtime": "^7.12.5",
"@types/raf": "^3.4.0",
"core-js": "^3.8.3",
"raf": "^3.4.1",
"regenerator-runtime": "^0.13.7",
"rgbcolor": "^1.0.1",
"stackblur-canvas": "^2.0.0",
"svg-pathdata": "^6.0.3"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/canvg/node_modules/core-js": {
"version": "3.45.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.45.1.tgz",
"integrity": "sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
}
},
"node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
......@@ -9372,6 +9454,15 @@
"node": ">= 8"
}
},
"node_modules/css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"license": "MIT",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/css-loader": {
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz",
......@@ -9977,6 +10068,16 @@
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/dompurify": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.6.tgz",
"integrity": "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==",
"license": "(MPL-2.0 OR Apache-2.0)",
"optional": true,
"optionalDependencies": {
"@types/trusted-types": "^2.0.7"
}
},
"node_modules/domutils": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
......@@ -10319,6 +10420,12 @@
"integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==",
"dev": true
},
"node_modules/es6-promise": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
"license": "MIT"
},
"node_modules/esbuild": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz",
......@@ -11212,6 +11319,12 @@
"resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="
},
"node_modules/fflate": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
"license": "MIT"
},
"node_modules/figures": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
......@@ -12094,6 +12207,30 @@
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
"node_modules/html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
"license": "MIT",
"dependencies": {
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/html2pdf.js": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/html2pdf.js/-/html2pdf.js-0.10.3.tgz",
"integrity": "sha512-RcB1sh8rs5NT3jgbN5zvvTmkmZrsUrxpZ/RI8TMbvuReNZAdJZG5TMfA2TBP6ZXxpXlWf9NB/ciLXVb6W2LbRQ==",
"license": "MIT",
"dependencies": {
"es6-promise": "^4.2.5",
"html2canvas": "^1.0.0",
"jspdf": "^3.0.0"
}
},
"node_modules/htmlparser2": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
......@@ -13161,6 +13298,33 @@
"node >= 0.2.0"
]
},
"node_modules/jspdf": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/jspdf/-/jspdf-3.0.1.tgz",
"integrity": "sha512-qaGIxqxetdoNnFQQXxTKUD9/Z7AloLaw94fFsOiJMxbfYdBbrBuhWmbzI8TVjrw7s3jBY1PFHofBKMV/wZPapg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.7",
"atob": "^2.1.2",
"btoa": "^1.2.1",
"fflate": "^0.8.1"
},
"optionalDependencies": {
"canvg": "^3.0.11",
"core-js": "^3.6.0",
"dompurify": "^3.2.4",
"html2canvas": "^1.0.0-rc.5"
}
},
"node_modules/jspdf/node_modules/@babel/runtime": {
"version": "7.28.3",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.3.tgz",
"integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/karma": {
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/karma/-/karma-6.4.2.tgz",
......@@ -15520,6 +15684,13 @@
"node": ">=8"
}
},
"node_modules/performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
"license": "MIT",
"optional": true
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
......@@ -16182,6 +16353,16 @@
}
]
},
"node_modules/raf": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
"license": "MIT",
"optional": true,
"dependencies": {
"performance-now": "^2.1.0"
}
},
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
......@@ -16564,6 +16745,16 @@
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
"integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
},
"node_modules/rgbcolor": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
"integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
"license": "MIT OR SEE LICENSE IN FEEL-FREE.md",
"optional": true,
"engines": {
"node": ">= 0.8.15"
}
},
"node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
......@@ -17438,6 +17629,16 @@
"node": "*"
}
},
"node_modules/stackblur-canvas": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
"integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">=0.1.14"
}
},
"node_modules/statuses": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
......@@ -17632,6 +17833,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/svg-pathdata": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
"integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/svg.draggable.js": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz",
......@@ -18039,6 +18250,15 @@
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="
},
"node_modules/text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"license": "MIT",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
......@@ -18447,6 +18667,15 @@
"node": ">= 0.4.0"
}
},
"node_modules/utrie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"license": "MIT",
"dependencies": {
"base64-arraybuffer": "^1.0.2"
}
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
......
......@@ -59,6 +59,7 @@
"glob-watcher": "^6.0.0",
"hammerjs": "^2.0.8",
"helmet": "^7.0.0",
"html2pdf.js": "^0.10.3",
"keen-slider": "^6.8.5",
"leaflet": "^1.9.4",
"lightgallery": "^2.1.2",
......@@ -102,6 +103,7 @@
"@types/d3-shape": "^3.1.1",
"@types/hammerjs": "^2.0.41",
"@types/jasmine": "~4.3.4",
"@types/jspdf": "^1.3.3",
"@types/leaflet": "^1.9.3",
"@types/mousetrap": "^1.6.11",
"@types/wnumb": "^1.2.1",
......
......@@ -617,7 +617,7 @@
<app-pms-idp [currentTap]="currentTap" [canSave]="canSave" [appraisalIdp]="compentency.data.idp"
[evaluaterId]="evaluaterId" [evaluateeId]="evaluateeId"
[canEdit]="evaluationForm=='sup'?canEdit:false" [currentStep]="compentency.data.currentStep"
[dateIso]="dateIso" (idpForm)="compentency.data.idp=$event" [complete]="complete"></app-pms-idp>
[dateIso]="dateIso" (idpForm)="compentency.data.idp=$event" [complete]="complete" [pdfPrint]="pdfPrint" (pdfPrinted)="onPdfPrinted()"></app-pms-idp>
</div>
<ng-container *ngIf="compentency.data&&canSave">
<div class="box-footer text-end space-x-3 rtl:space-x-reverse"
......@@ -626,6 +626,11 @@
<textarea type="text" class="ti-form-input" rows="2" placeholder="ใส่ Comment ที่นี่"
[(ngModel)]="comment"></textarea>
</div>
<button (click)="toggleStatusPdfPrint()" class="ti-btn m-0 ti-btn-soft-warning"
*ngIf="currentTap == 'แผนพัฒนาบุคลากร'">
<i class="ri-draft-fill"></i>
PDF
</button>
<button (click)="save('approve')" class="ti-btn m-0 ti-btn-soft-secondary"
[disabled]="compentencyFormRemain||kpiFormRemain"
[class.ti-btn-disabled]="compentencyFormRemain||kpiFormRemain">
......
......@@ -8,3 +8,18 @@
opacity: 1;
}
}
@media print {
body * {
visibility: hidden; /* ซ่อนทุก element */
}
#printArea, #printArea * {
visibility: visible; /* แสดงเฉพาะ #printArea */
}
#printArea {
position: absolute;
left: 0;
top: 0;
width: 100%;
}
}
......@@ -74,7 +74,7 @@ export class PmsFormEmployeeComponent {
complete = false
@ViewChild('scrollContainer') scrollContainer!: ElementRef;
pdfPrint = false;
constructor(
private router: Router,
......@@ -759,4 +759,14 @@ export class PmsFormEmployeeComponent {
const imgElement = event.target as HTMLImageElement;
imgElement.src = './assets/img/users/defaultperson.jpg';
}
toggleStatusPdfPrint() {
this.pdfPrint = !this.pdfPrint; // สลับ true/false เพื่อให้ Child จับการเปลี่ยน
}
onPdfPrinted() {
// เมื่อ Child แจ้งว่าพิมพ์เสร็จ ให้รีเซ็ตกลับเป็น false
this.pdfPrint = false;
}
}
<ng-container *ngTemplateOutlet="idpEvaluation"></ng-container>
<ng-template #idpEvaluation>
<ng-container *ngIf="appraisalIdp">
<div style="overflow-y: auto;" style="padding-top: 1rem">
<div style="overflow-y: auto; padding-top: 1rem" #pdfArea class="pdf-container">
<div class="pb-2">
<div class="font-size-18px font-weight-700 text-gray-500">
ส่วนที่ 1: ข้อมูลทั่วไป
......@@ -283,11 +283,12 @@
<div class="flex !items-center" style="min-height: 100px;">
{{competencyCourse.tdesc}}
<span class="ciricon border cursor-pointer"
*ngIf="canEdit&&appraisalIdp.masfromEvaluationIdp.idpStatus=='1'"
*ngIf="canEdit&&appraisalIdp.masfromEvaluationIdp.idpStatus=='1' && pdfPrintCheck == 0"
(click)="deleteCompetencyCourse(i,l)">
<i class="ri-close-line text-red-500"></i>
</span>
</div>
<div *ngIf="pdfPrintCheck == 0">
<button
*ngIf="last&&canEdit&&appraisalIdp.masfromEvaluationIdp.idpStatus=='1'"
type="button"
......@@ -296,16 +297,20 @@
<i class="ri-add-line"></i>
Add
</button>
</div>
</ng-container>
</ng-container>
<ng-container
*ngIf="canEdit&&!data.competencyCourse?.length&&appraisalIdp.masfromEvaluationIdp.idpStatus=='1'&&data.idpDevelopmentPlan?.training">
<div *ngIf="pdfPrintCheck == 0">
<button type="button"
class="ti-btn ti-btn-soft-secondary h-45px m-0 shadow-md"
(click)="openCompetencycourseDialog(i)">
<i class="ri-add-line"></i>
Add
</button>
</div>
</ng-container>
</td>
<td class="!p-0"></td>
......@@ -315,6 +320,8 @@
*ngIf="appraisalIdp.masfromEvaluationRound.apsPeriodStart &&appraisalIdp.masfromEvaluationRound.apsPeriodEnd">
จาก&nbsp;
</ng-container>
<ng-container *ngIf="pdfPrintCheck == 0">
<ng-container
*ngIf="data.idpDevelopmentPlan&&data.idpDevelopmentPlan?.training && appraisalIdp.apsapprove1.employeeId == evaluaterId">
<input type="date" id="input-label" class="ti-form-input"
......@@ -335,6 +342,18 @@
</ng-container>
{{convertDateFormat(appraisalIdp.masfromEvaluationRound.apsPeriodEnd)}}
</ng-container>
</ng-container>
<ng-container *ngIf="pdfPrintCheck == 1">
{{convertDateFormat(appraisalIdp.masfromEvaluationRound.apsPeriodStart)}}
<ng-container
*ngIf="appraisalIdp.masfromEvaluationRound.apsPeriodStart &&appraisalIdp.masfromEvaluationRound.apsPeriodEnd">
<p></p>ถึง&nbsp;
</ng-container>
{{convertDateFormat(appraisalIdp.masfromEvaluationRound.apsPeriodEnd)}}
</ng-container>
</td>
</tr>
</ng-container>
......
@media print {
body * {
visibility: hidden; /* ซ่อนทุก element */
}
#printArea, #printArea * {
visibility: visible; /* แสดงเฉพาะ #printArea */
}
#printArea {
position: absolute;
left: 0;
top: 0;
width: 100%;
}
}
.pdf-container {
/* เอาตามที่คุณมีได้เลย */
background: #fff;
padding: 10px;
transform: translateZ(0);
}
.pdf-container table {
// table-layout: fixed;
width: 100%;
// word-break: break-word;
white-space: normal;
}
.page-break {
break-after: page; /* modern */
page-break-after: always; /* legacy */
}
.no-break {
break-inside: avoid;
page-break-inside: avoid;
}
.pdf-header {
display: flex;
gap: 12px;
align-items: center;
img {
width: 72px;
height: 72px;
object-fit: cover;
border-radius: 50%;
}
}
/* ตารางใน PDF ให้ไม่แตกกลางหน้า */
table, .card, .section-block {
break-inside: avoid;
page-break-inside: avoid;
}
.pdf-container > :last-child {
margin-bottom: 0 !important;
padding-bottom: 0 !important;
}
// .pdf-container .page-break:last-child {
// page-break-after: auto !important;
// break-after: auto !important;
// }
import { ChangeDetectorRef, Component, EventEmitter, Input, Output, SimpleChanges, ViewChild } from '@angular/core';
import { ChangeDetectorRef, Component, ElementRef, EventEmitter, Input, Output, SimpleChanges, ViewChild } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { Idp } from 'src/app/shared/model/competency.model';
import { CompetencycourseMiniModel, MyCompetencycourseMiniModel } from 'src/app/shared/model/competencycourse-mini.model';
......@@ -35,6 +35,10 @@ export class PmsIdpComponent {
@Input() currentStep = ""
@Input() currentTap = ""
@Output() idpForm: EventEmitter<any> = new EventEmitter<any>();
@Input() pdfPrint = false;
@Output() pdfPrinted = new EventEmitter<void>();
pdfPrintCheck = 0
@ViewChild('pdfArea') pdfArea!: ElementRef<HTMLElement>;
competencycourse: { loading: boolean, data: CompetencycourseMiniModel[] } = { loading: false, data: [] }
competencycourseTable: table = {
......@@ -58,6 +62,17 @@ export class PmsIdpComponent {
this.getCompetencycourseMiniList()
}
ngOnChanges(changes: SimpleChanges): void {
if (changes['pdfPrint']) {
const { previousValue, currentValue } = changes['pdfPrint'];
console.log('pdfPrint changed:', previousValue, '→', currentValue);
// สั่งพิมพ์เฉพาะตอนเป็น true
if (currentValue === true) {
this.pdfPrintCheck = 1
this.exportPdf();
this.pdfPrinted.emit(); // แจ้ง Parent ให้รีเซ็ต flag
}
}
if (changes['currentTap']?.currentValue || changes['appraisalIdp']?.currentValue) {
this.getFormIdp()
}
......@@ -173,4 +188,164 @@ export class PmsIdpComponent {
this.idpForm.emit(this.appraisalIdp)
}
print() {
window.print();
}
/** ล็อคความกว้างเทียบ A4 (≈794px @96dpi) ให้ layout เสถียรตอนแคปเจอร์ */
private freezeWidthForA4(el: HTMLElement) {
const prev = {
width: el.style.width,
maxWidth: el.style.maxWidth,
transform: el.style.transform,
transformOrigin: el.style.transformOrigin,
};
el.style.width = '794px';
el.style.maxWidth = '794px';
el.style.transformOrigin = 'top left';
el.style.transform = 'scale(1)';
return () => {
el.style.width = prev.width;
el.style.maxWidth = prev.maxWidth;
el.style.transform = prev.transform;
el.style.transformOrigin = prev.transformOrigin;
};
}
/** ขยายเป็นความกว้างจริง (scrollWidth) แล้วสเกลลงให้พอดี A4 */
private expandToFullWidthThenScale(el: HTMLElement) {
const A4_PX = 794; // ≈ 210mm @ 96dpi
const full = el.scrollWidth; // ความกว้างจริงทั้งหมด (รวมพื้นที่ต้องเลื่อนขวา)
const scale = Math.min(1, A4_PX / full); // สเกลลงให้พอดี A4 (ถ้ากว้างกว่า)
// เก็บค่าเดิมไว้คืนทีหลัง
const prev = {
width: el.style.width,
maxWidth: el.style.maxWidth,
overflowX: el.style.overflowX,
transform: el.style.transform,
transformOrigin: el.style.transformOrigin,
};
// คลี่ความกว้างออกทั้งหมด แล้วสเกลให้พอดี A4
el.style.width = `${full}px`;
el.style.maxWidth = 'none';
el.style.overflowX = 'visible';
el.style.transformOrigin = 'top left';
el.style.transform = `scale(${scale})`;
// คืนค่า
return () => {
el.style.width = prev.width;
el.style.maxWidth = prev.maxWidth;
el.style.overflowX = prev.overflowX;
el.style.transform = prev.transform;
el.style.transformOrigin = prev.transformOrigin;
};
}
/** ทำให้ทุกกล่องใน subtree ไม่ตัดขอบขวา: overflowX => visible, ยกเลิก position:sticky ชั่วคราว */
private unclipOverflows(el: HTMLElement) {
const patched: Array<{node: HTMLElement, prev: Partial<CSSStyleDeclaration>}> = [];
const walker = document.createTreeWalker(el, NodeFilter.SHOW_ELEMENT);
const patchNode = (node: HTMLElement) => {
const style = window.getComputedStyle(node);
const needOverflowPatch = style.overflowX !== 'visible' || style.overflow !== 'visible';
const isSticky = style.position === 'sticky';
if (needOverflowPatch || isSticky) {
const prev = {
overflow: node.style.overflow,
overflowX: node.style.overflowX,
overflowY: node.style.overflowY,
position: node.style.position,
clipPath: (node.style as any).clipPath,
};
patched.push({ node, prev });
node.style.overflow = 'visible';
node.style.overflowX = 'visible';
node.style.overflowY = 'visible';
if (isSticky) node.style.position = 'static';
(node.style as any).clipPath = 'none';
}
};
// รวม el เองด้วย
patchNode(el as HTMLElement);
while (walker.nextNode()) {
patchNode(walker.currentNode as HTMLElement);
}
// ฟังก์ชันคืนค่าเดิม
return () => {
for (const { node, prev } of patched) {
node.style.overflow = prev.overflow || '';
node.style.overflowX = prev.overflowX || '';
node.style.overflowY = prev.overflowY || '';
node.style.position = prev.position || '';
(node.style as any).clipPath = prev.clipPath || '';
}
};
}
// @ViewChild('pdfArea') pdfArea!: ElementRef<HTMLElement>;
async exportPdf() {
const el = this.pdfArea?.nativeElement;
if (!el) return;
const mod: any = await import('html2pdf.js');
const html2pdf = mod.default ?? mod;
// 1) คลี่กว้างจริงแล้วสเกลลงพอดี A4
const cleanupScale = this.expandToFullWidthThenScale(el);
// 2) ปลดคลิป overflow/sticky ของลูก ๆ ทั้งหมด
const cleanupUnclip = this.unclipOverflows(el);
const prevBodyOverflow = document.body.style.overflow;
document.body.style.overflow = 'hidden';
// ขนาดจริงของ element (หลังถูกขยายแล้ว)
const fullW = el.scrollWidth;
const fullH = el.scrollHeight;
const epsilon = 2; // กันเผื่อ
const opt = {
margin: [10,10,10,10],
filename: `pms-${this.evaluateeId || 'employee'}-${new Date().toISOString().slice(0,10)}.pdf`,
image: { type: 'jpeg', quality: 0.96 },
html2canvas: {
scale: 2,
useCORS: true,
logging: false,
scrollX: 0,
scrollY: -window.scrollY,
// 👇 บอกขนาดที่จะเรนเดอร์ให้เท่าของจริงทั้งหมด
width: 800,
// height: fullH,
height: Math.max(0, fullH - epsilon),
windowWidth: 800,
// windowHeight: fullH,
windowHeight: Math.max(0, fullH - epsilon),
// foreignObjectRendering: true, // ลองเปิดถ้า layout ยังเพี้ยน (มีข้อจำกัดกับบางเคส)
},
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' },
pagebreak: { mode: ['css','legacy'], avoid: ['.no-break','table','img'] }
};
try {
await html2pdf().from(el).set(opt).save();
} finally {
cleanupUnclip();
cleanupScale();
document.body.style.overflow = prevBodyOverflow;
}
this.pdfPrintCheck = 0
}
}
declare module 'html2pdf.js' {
const html2pdf: any;
export default html2pdf;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment