UNPKG

@canes/ecb-tas-feature

Version:
1,271 lines (1,246 loc) 111 kB
/* Version: 2.3.3 - July 26, 2025 11:10:21 */ import { axiosBuilder, AppContext } from '@ecoba-vn/client-core'; import { jsx, jsxs, Fragment } from 'react/jsx-runtime'; import React, { useContext, useState, useEffect } from 'react'; import { IconButton, DataTable, FormDialog, ComboBox, DateInput, Frame, TextField } from '@ecoba-vn/client-shared-ui'; import { withStyles, Switch, Grid, FormLabel, RadioGroup, FormControlLabel, Radio, makeStyles, Typography, Chip, Table, TableHead, TableRow, TableCell, TableBody, Tooltip } from '@material-ui/core'; import moment from 'moment'; import clsx from 'clsx'; import { makeStyles as makeStyles$1 } from '@material-ui/core/styles'; import { amber, green, blue } from '@material-ui/core/colors'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; const baseUrl$8 = `${process.env.REACT_APP_API_HOSTNAME}`; const MOD_ROLE = "MOD_ROLE"; const IT_SUPPORT_ROLE = "IT_SUPPORT_ROLE"; function checkPermission$5() { // return axiosBuilder // .getInstance(baseUrl) // .get("api/v1/tas/user-roles/users/check-permission") // .then((res) => res.data) // .catch(() => false); return Promise.resolve(true); } function checkModRolePermission() { return axiosBuilder .getInstance(baseUrl$8) .get(`api/v1/tas/user-roles/users/check-role-permission?role=${MOD_ROLE}`) .then((res) => res.data) .catch(() => false); // return Promise.resolve(true); } function checkItSupportRolePermission() { return axiosBuilder .getInstance(baseUrl$8) .get(`api/v1/tas/user-roles/users/check-role-permission?role=${IT_SUPPORT_ROLE}`) .then((res) => res.data) .catch(() => false); } function getAll$4() { return axiosBuilder .getInstance(baseUrl$8) .get("api/v1/u/users") .then((res) => res.data); } const userService = { getAll: getAll$4, checkPermission: checkPermission$5, checkModRolePermission, checkItSupportRolePermission, }; /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; const baseUrl$7 = `${process.env.REACT_APP_API_HOSTNAME}`; const api$4 = "api/v1/tas/employees"; function getAll$3() { return axiosBuilder .getInstance(baseUrl$7) .get(`${api$4}/items`) .then((res) => res.data); } function getByUserNumber(userNumber) { return axiosBuilder .getInstance(baseUrl$7) .get(`${api$4}/items/${userNumber}`) .then((res) => res.data); } function getQuotaByDate(date) { return axiosBuilder .getInstance(baseUrl$7) .get(`${api$4}/items/me/quota/${date}`) .then((res) => res.data); } function create$3(model) { return axiosBuilder .getInstance(baseUrl$7) .post(`${api$4}/items`, model) .then((res) => res.data); } function update$1(model) { return axiosBuilder .getInstance(baseUrl$7) .put(`${api$4}/items`, model) .then((res) => res.data); } function remove$3(userNumber) { return axiosBuilder .getInstance(baseUrl$7) .delete(`${api$4}/${userNumber}`) .then((res) => res.data); } const employeeService = { getAll: getAll$3, getByUserNumber, getQuotaByDate, create: create$3, update: update$1, remove: remove$3, }; function formatDate$2(date, formatString = "dd/MM/yyyy") { let result = formatString; const format = [ { symbol: "dd", value: date.getDate() < 10 ? `0${date.getDate()}` : date.getDate(), }, { symbol: "MM", value: date.getMonth() + 1 < 10 ? `0${date.getMonth() + 1}` : `${date.getMonth() + 1}`, }, { symbol: "yyyy", value: date.getFullYear(), }, { symbol: "hh", value: date.getHours() < 10 ? `0${date.getHours()}` : date.getHours(), }, { symbol: "mm", value: date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes(), }, ]; format.map((f) => { result = result.replace(f.symbol, f.value); return f.symbol; }); return result; } function formatMoney$1(value, frac = 0) { const numberFormat = new Intl.NumberFormat("vi-VN", { maximumFractionDigits: frac, minimumFractionDigits: frac, }); return numberFormat.format(value); } const format$1 = { formatDate: formatDate$2, formatMoney: formatMoney$1, }; const formatJoiningDate = (value) => format$1.formatDate(new Date(value.joiningDate), "dd/MM/yyyy"); const formatJoiningDateToString = (value) => format$1.formatDate(new Date(value), "yyyy-MM-dd"); const dataColumn$2 = [ { id: "userNumber", label: "Nhân viên", numeric: false, sortable: true, }, { id: "gender", label: "Giới tính", numeric: false, sortable: true }, { id: "joiningDate", label: "Ngày gia nhập", numeric: false, sortable: false, format: formatJoiningDate, }, { id: "type", label: "Nhân viên", numeric: false, sortable: false, }, { id: "action", label: "", numeric: false, sortable: false, }, ]; const InitEmployee = { userNumber: "", isMale: false, isOfficial: false, joiningDate: moment(new Date(Date.now()).toString()).format("YYYY/MM/DD"), }; const initUser = { username: "", employeeId: "", displayName: "", }; function Employees() { const { setStatus, showAlert } = useContext(AppContext); const [employees, setEmployees] = useState([]); const [users, setUsers] = useState([]); const [openForm, setOpenForm] = useState(false); const [employee, setEmployee] = useState(InitEmployee); const [userSelected, setUserSelected] = useState(initUser); const [isEdit, setIsEdit] = useState(false); const ButtonAction = [ // eslint-disable-next-line react/jsx-key jsx(IconButton, { icon: "plus", text: "Th\u00EAm", onClick: () => setOpenForm(true), variant: "text" }, void 0), ]; const renderData = (data) => { return data .map((item) => { const user = users.find((x) => x.employeeId == item.userNumber); // if (user == null) { // alert(item.userNumber); // } const row = Object.assign(Object.assign({}, item), { userNumber: user != null ? user.displayName : item.userNumber, gender: item.isMale ? "Nam" : "Nữ", type: item.isOfficial ? "Chính thức" : "Thử việc", action: (jsxs(Fragment, { children: [jsx(IconButton, { icon: "edit", text: "S\u1EEDa", tooltip: "S\u1EEDa th\u00F4ng tin nh\u00E2n vi\u00EAn", color: "primary", variant: "text", onClick: () => { handleEnableEdit(item.userNumber); setEmployee(item); setOpenForm(true); } }, void 0), jsx(IconButton, { icon: "trash-alt", text: "Xo\u00E1", tooltip: "Xo\u00E1 th\u00F4ng tin nh\u00E2n vi\u00EAn", color: "danger", variant: "text", onClick: () => handleDelete(item.userNumber) }, void 0)] }, void 0)) }); return row; }) .sort((e1, e2) => { if (parseInt(e1.userNumber) > parseInt(e2.userNumber)) return 1; if (parseInt(e1.userNumber) < parseInt(e2.userNumber)) return -1; return 0; }); }; const refresh = () => __awaiter(this, void 0, void 0, function* () { setStatus(true, ""); try { setEmployees(yield (yield employeeService.getAll()).map((x) => { const date = moment(x.joiningDate).format("YYYY/MM/DD"); return Object.assign(Object.assign({}, x), { joiningDate: date }); })); setUsers(yield userService.getAll()); } catch (error) { showAlert("error", "Tải dữ liệu thất bại! Vui lòng thử lại sau hoặc kiểm tra kết nối mạng."); } finally { setStatus(false, ""); } }); useEffect(() => { refresh(); }, []); const handleEnableEdit = (userNumber) => { const user = users.find((x) => x.employeeId == userNumber); if (user != null) setUserSelected(user); setIsEdit(true); }; const handleCloseForm = () => { setOpenForm(false); setEmployee(InitEmployee); setUserSelected(initUser); }; const handleChangeOfficial = (event, checked) => { setEmployee(Object.assign(Object.assign({}, employee), { [event.target.name]: checked === "true" || checked == true })); }; const handleChangeUserNumber = (user) => { setUserSelected(user); setEmployee(Object.assign(Object.assign({}, employee), { userNumber: user.employeeId })); }; const handleChangeDate = (date) => { setEmployee(Object.assign(Object.assign({}, employee), { joiningDate: date })); }; const handleSubmit = () => __awaiter(this, void 0, void 0, function* () { setStatus(true, ""); try { if (!isEdit) { yield employeeService.create({ userNumber: employee.userNumber, isOfficial: employee.isOfficial, joiningDate: formatJoiningDateToString(new Date(employee.joiningDate)), isMale: employee.isMale, }); } yield employeeService.update({ userNumber: employee.userNumber, isOfficial: employee.isOfficial, joiningDate: formatJoiningDateToString(new Date(employee.joiningDate)), isMale: employee.isMale, }); showAlert("success", "Thành công"); handleCloseForm(); refresh(); } catch (ex) { showAlert("error", "Thao tác thất bai! Vui lòng thử lại hoặc kiểm tra kết nối mạng."); } finally { setStatus(false, ""); } }); const handleDelete = (userNumber) => __awaiter(this, void 0, void 0, function* () { setStatus(true, ""); try { yield employeeService.remove(userNumber); showAlert("success", "Thành công"); refresh(); } catch (_a) { showAlert("error", "Thao tác thất bai! Vui lòng thử lại hoặc kiểm tra kết nối mạng."); } finally { setStatus(false, ""); } }); return (jsxs(Fragment, { children: [jsx(ModelForm, { users: users, userSelected: userSelected, employee: employee, open: openForm, onClose: handleCloseForm, onChangeOfficial: handleChangeOfficial, onChangeUserNumber: handleChangeUserNumber, onChangeDate: handleChangeDate, onSubmit: handleSubmit }, void 0), jsx(DataTable, { actions: ButtonAction, columns: dataColumn$2, data: renderData(employees), title: "Danh s\u00E1ch nh\u00E2n vi\u00EAn", initialOrderBy: "userNumber" }, void 0)] }, void 0)); } const AntSwitch = withStyles((theme) => ({ root: { width: 28, height: 16, padding: 0, display: "flex", }, switchBase: { padding: 2, color: theme.palette.grey[500], "&$checked": { transform: "translateX(12px)", color: theme.palette.common.white, "& + $track": { opacity: 1, backgroundColor: theme.palette.primary.main, borderColor: theme.palette.primary.main, }, }, }, thumb: { width: 12, height: 12, boxShadow: "none", }, track: { border: `1px solid ${theme.palette.grey[500]}`, borderRadius: 16 / 2, opacity: 1, backgroundColor: theme.palette.common.white, }, checked: {}, }))(Switch); const ModelForm = ({ users, userSelected, employee, open, onClose, onChangeOfficial, onChangeUserNumber, onChangeDate, onSubmit, }) => { return (jsx(FormDialog, Object.assign({ title: "Th\u00EAm/s\u1EEDa nh\u00E2n vi\u00EAn", open: open, onClose: onClose, onSubmit: onSubmit }, { children: jsxs(Grid, Object.assign({ container: true, spacing: 1 }, { children: [jsx(Grid, Object.assign({ item: true, xs: 12 }, { children: jsx(ComboBox, { label: "Nh\u00E2n vi\u00EAn", optionLabel: "displayName", options: users, getOptionSelected: (o, v) => o.employeeId == v.employeeId, onChange: (value) => { if (value != null || value != undefined) onChangeUserNumber(value); }, value: userSelected }, void 0) }), void 0), jsxs(Grid, Object.assign({ item: true, xs: 12 }, { children: [jsx(FormLabel, Object.assign({ component: "legend" }, { children: "Gi\u1EDBi t\u00EDnh" }), void 0), jsxs(RadioGroup, Object.assign({ "aria-label": "gender", name: "isMale", value: `${employee.isMale}`, onChange: onChangeOfficial }, { children: [jsx(FormControlLabel, { value: "true", control: jsx(Radio, {}, void 0), label: "Nam" }, void 0), jsx(FormControlLabel, { value: "false", control: jsx(Radio, {}, void 0), label: "N\u1EEF" }, void 0)] }), void 0)] }), void 0), jsx(Grid, Object.assign({ item: true, xs: 12 }, { children: jsx(DateInput, { format: "YYYY/MM/DD", value: employee.joiningDate, onChange: (v) => onChangeDate(v) }, void 0) }), void 0), jsxs(Grid, Object.assign({ item: true, xs: 12 }, { children: [jsx(FormLabel, Object.assign({ component: "legend" }, { children: "Lo\u1EA1i" }), void 0), jsxs(Grid, Object.assign({ component: "label", container: true, alignItems: "center", spacing: 1 }, { children: [jsx(Grid, Object.assign({ item: true }, { children: jsx(AntSwitch, { name: "isOfficial", checked: employee.isOfficial, onChange: onChangeOfficial }, void 0) }), void 0), jsx(Grid, Object.assign({ item: true }, { children: "Ch\u00EDnh th\u1EE9c" }), void 0)] }), void 0)] }), void 0)] }), void 0) }), employee.userNumber)); }; function formatDate$1(date, formatString = 'dd/MM/yyyy') { let result = formatString; const format = [ { symbol: 'dd', value: date.getDate() < 10 ? `0${date.getDate()}` : date.getDate(), }, { symbol: 'MM', value: date.getMonth() + 1 < 10 ? `0${date.getMonth() + 1}` : `${date.getMonth() + 1}`, }, { symbol: 'yyyy', value: date.getFullYear(), }, { symbol: 'hh', value: date.getHours() < 10 ? `0${date.getHours()}` : date.getHours(), }, { symbol: 'mm', value: date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes(), }, ]; format.map((f) => { result = result.replace(f.symbol, f.value); return f.symbol; }); return result; } function formatMoney(value, frac = 0) { const numberFormat = new Intl.NumberFormat('vi-VN', { maximumFractionDigits: frac, minimumFractionDigits: frac }); return numberFormat.format(value); } const format = { formatDate: formatDate$1, formatMoney, }; const baseUrl$6 = `${process.env.REACT_APP_API_HOSTNAME}`; function DownloadButton({ filename, url, label = "", variant = "text", }) { const [isLoading, setIsLoading] = useState(false); const [percent, setPercent] = useState(0); const handleDownload = () => __awaiter(this, void 0, void 0, function* () { setIsLoading(true); return axiosBuilder .getInstance(baseUrl$6) .get(url, { responseType: "blob", onDownloadProgress: (progressEvent) => { console.log((progressEvent.loaded / progressEvent.total) * 100); setPercent(Math.floor((progressEvent.loaded / progressEvent.total) * 100)); }, }) .then((res) => { const href = URL.createObjectURL(res.data); const link = document.createElement("a"); link.href = href; link.setAttribute("download", filename); document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(href); setIsLoading(false); }) .catch((err) => err); }); return (jsx(IconButton, { color: "primary", tooltip: "T\u1EA3i file v\u1EC1 m\u00E1y", text: isLoading ? `Đã tải: ${percent}` : label, icon: "download", variant: variant, disabled: isLoading, onClick: () => { handleDownload(); } }, void 0)); } const useStyles$1 = makeStyles(() => ({ container: { maxWidth: "800px", width: "100%", background: "#fff", padding: "15px", borderRadius: "6px", display: "block", margin: "0px auto", }, blockDownload: { width: "100%", marginTop: "10px", textAlign: "center", }, })); function Download() { const classes = useStyles$1(); const [startDateString, setStartDateString] = useState(format.formatDate(new Date(), "yyyy-MM-dd")); const [endDateString, setEndDateString] = useState(format.formatDate(new Date(), "yyyy-MM-dd")); const [year, setYear] = useState(`${new Date().getFullYear()}`); return (jsxs(Frame, Object.assign({ title: "T\u1EA3i b\u00E1o c\u00E1o \u0111\u0103ng k\u00FD v\u1EAFng m\u1EB7t" }, { children: [jsx(DateInput, { label: "Ng\u00E0y b\u1EAFt \u0111\u1EA7u (yyyy-mm-dd)", format: "YYYY-MM-DD", value: startDateString, onChange: (v) => setStartDateString(v) }, void 0), jsx(DateInput, { label: "Ng\u00E0y k\u1EBFt th\u00FAc (yyyy-mm-dd)", format: "YYYY-MM-DD", value: endDateString, onChange: (v) => setEndDateString(v) }, void 0), jsx("div", Object.assign({ className: classes.blockDownload }, { children: jsx(DownloadButton, { label: "Download b\u00E1o c\u00E1o", filename: `Report_${startDateString}_${endDateString}.xlsx`, url: `/api/v1/tas/reports/by-date?start_date=${startDateString}&end_date=${endDateString}` }, void 0) }), void 0), jsxs("div", Object.assign({ className: classes.blockDownload }, { children: [jsx(TextField, { label: "Number", type: "number", value: year, onChange: (e) => setYear(e.target.value) }, void 0), jsx(DownloadButton, { label: "Download d\u1EEF li\u1EC7u ph\u00E9p", filename: `Report_Quota.xlsx`, url: `/api/v1/tas/reports/quota/${year}/download` }, void 0)] }), void 0)] }), void 0)); } const baseUrl$5 = `${process.env.REACT_APP_API_HOSTNAME}`; function getTimeEvent(year, month) { const uri = `api/v1/tas/time-events/${year}/${month}`; return axiosBuilder .getInstance(baseUrl$5) .get(uri) .then((res) => res.data); } function addDaysOffFromExcel(file) { const formData = new FormData(); formData.append("files", file, file.name); const uri = `api/v1/tas/employees/days-off/upload-from-excel`; return axiosBuilder.getInstance(baseUrl$5).post(uri, formData, { headers: { "Content-Type": "multipart/form-data", }, }); } function UploadQuota() { const { setStatus, showAlert } = useContext(AppContext); const fileInputRef = React.useRef(null); const handleSubmitUploadDayOff = (files) => __awaiter(this, void 0, void 0, function* () { setStatus(true, ""); if (files.length >= 1) { try { yield addDaysOffFromExcel(files[0]); showAlert("success", "Thành công"); } catch (_a) { showAlert("error", "Thao tác thất bai! Vui lòng thử lại hoặc kiểm tra kết nối mạng."); } finally { setStatus(false, ""); } } }); return (jsxs(Fragment, { children: [jsx(IconButton, { icon: "upload", text: "Upload days off", color: "primary", variant: "contained", tooltip: "Upload file excel days off", onClick: () => { var _a; (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); } }, void 0), jsx("input", { style: { display: "none" }, type: "file", accept: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", onChange: (e) => { if (e.currentTarget.files !== null) { handleSubmitUploadDayOff([...e.currentTarget.files]); } }, ref: fileInputRef }, void 0)] }, void 0)); } const baseUrl$4 = `${process.env.REACT_APP_API_HOSTNAME}`; const api$3 = "api/v1/tas/transactions"; function syncStatus(year, month) { return axiosBuilder .getInstance(baseUrl$4) .get(`${api$3}/sync/status/${year}/${month}`) .then((res) => res.data); } function sync(date) { return axiosBuilder .getInstance(baseUrl$4) .post(`${api$3}/sync/${format.formatDate(new Date(date), 'yyyy-MM-dd')}`); } const service = { syncStatus, sync, }; const formatDate = (value) => format$1.formatDate(new Date(value.date), "dd/MM/yyyy"); const dataColumn$1 = [ { id: "date", label: "Ngày", numeric: false, sortable: true, format: formatDate }, { id: "external", label: "Máy chấm công", numeric: true, sortable: false }, { id: "internal", label: "Hệ thống", numeric: true, sortable: false }, { id: "action", label: "", numeric: false, sortable: false }, ]; function Transactions() { const { setStatus, showAlert } = useContext(AppContext); const [data, setData] = useState([]); const [month, setMonth] = React.useState(new Date().getMonth() + 1); const [year, setYear] = React.useState(new Date().getFullYear()); const handleSync = (date) => __awaiter(this, void 0, void 0, function* () { setStatus(true, "Đang đồng bộ dữ liệu ..."); try { yield service.sync(date); refresh(year, month); } catch (error) { showAlert("error", "Thao tác thất bại! Vui lòng thử lại sau hoặc kiểm tra kết nối mạng."); setStatus(false, ""); } }); const handlePlus = () => { if (month === 12) { setMonth(1); setYear(year + 1); } else { setMonth(month + 1); } }; const handleMinus = () => { if (month === 1) { setMonth(12); setYear(year - 1); } else { setMonth(month - 1); } }; const actions = [ jsxs(Grid, Object.assign({ item: true, xs: 12, style: { padding: "16px", display: "flex", flexDirection: "row", alignItems: "center", } }, { children: [jsx(IconButton, { icon: "chevron-left", onClick: handleMinus }, void 0), jsx(Typography, Object.assign({ variant: "subtitle2" }, { children: `${month}/${year}` }), void 0), jsx(IconButton, { icon: "chevron-right", onClick: handlePlus }, void 0)] }), "action") ]; const renderData = (data) => { return data .map((item) => { const row = Object.assign(Object.assign({}, item), { action: (jsx(Fragment, { children: item.external > item.internal && (jsx(IconButton, { icon: "sync-alt", text: "\u0110\u1ED3ng b\u1ED9", tooltip: "\u0110\u1ED3ng b\u1ED9 d\u1EEF li\u1EC7u", color: "primary", variant: "text", onClick: () => { handleSync(item.date); } }, void 0)) }, void 0)) }); return row; }); }; const refresh = (year, month) => __awaiter(this, void 0, void 0, function* () { setStatus(true, "Đang tải dữ liệu ..."); try { setData(yield service.syncStatus(year, month)); } catch (error) { showAlert("error", "Tải dữ liệu thất bại! Vui lòng thử lại sau hoặc kiểm tra kết nối mạng."); } finally { setStatus(false, ""); } }); useEffect(() => { refresh(year, month); }, [year, month]); return (jsx(DataTable, { actions: actions, columns: dataColumn$1, data: renderData(data), title: "\u0110\u1ED3ng b\u1ED9 d\u1EEF li\u1EC7u", initialOrderBy: "date" }, void 0)); } const baseUrl$3 = `${process.env.REACT_APP_API_HOSTNAME}`; const api$2 = "api/v1/tas/managers"; function getAll$2() { return axiosBuilder .getInstance(baseUrl$3) .get(`${api$2}`) .then((res) => res.data); } function create$2(userNumber) { return axiosBuilder .getInstance(baseUrl$3) .post(`${api$2}/${userNumber}`) .then((res) => res.data); } function remove$2(userNumber) { return axiosBuilder .getInstance(baseUrl$3) .delete(`${api$2}/${userNumber}`) .then((res) => res.data); } const managerService = { getAll: getAll$2, create: create$2, remove: remove$2, }; function Managers() { const { showAlert, setStatus } = React.useContext(AppContext); const [users, setUsers] = React.useState([]); const [managers, setManagers] = React.useState([]); const [userSelect, setUserSelect] = React.useState(null); const handleAdd = () => __awaiter(this, void 0, void 0, function* () { if (userSelect === null) return; setStatus(true, "Đang thêm..."); try { yield managerService.create(userSelect.employeeId); refresh(); } catch (error) { showAlert("error", "Thêm không thành công! Vui lòng thử lại sau."); } finally { setStatus(false, ""); } }); const handleRemove = (userNumber) => __awaiter(this, void 0, void 0, function* () { setStatus(true, "Đang xoá..."); try { yield managerService.remove(userNumber); refresh(); } catch (error) { showAlert("error", "Xoá không thành công! Vui lòng thử lại sau."); } finally { setStatus(false, ""); } }); const refresh = () => __awaiter(this, void 0, void 0, function* () { setStatus(true, "Đang lấy dữ liệu..."); try { setUsers(yield userService.getAll()); setManagers(yield managerService.getAll()); } catch (error) { showAlert("error", "Lấy dữ liệu không thành công! Vui lòng thử lại sau."); } finally { setStatus(false, ""); } }); React.useEffect(() => { refresh(); }, []); return (jsxs(Frame, Object.assign({ title: "Qu\u1EA3n l\u00FD ph\u00EA duy\u1EC7t ch\u1EA5m c\u00F4ng" }, { children: [jsx(ComboBox, { options: users, getOptionSelected: (o, v) => o.employeeId === v.employeeId, optionLabel: "displayName", onChange: (value) => setUserSelect(value) }, void 0), jsx(IconButton, { icon: "plus", text: "Th\u00EAm", variant: "contained", onClick: handleAdd }, void 0), jsx(Grid, Object.assign({ xs: 12 }, { children: managers && managers.map((u) => (jsx(Chip, { color: u.userNumber === (userSelect === null || userSelect === void 0 ? void 0 : userSelect.employeeId) ? "primary" : "default", label: u.displayName, onDelete: () => handleRemove(u.userNumber) }, u.userNumber))) }), void 0)] }), void 0)); } const baseUrl$2 = `${process.env.REACT_APP_API_HOSTNAME}`; const api$1 = "api/v1/tas/holidays"; function getAll$1(year = null, month = null) { return __awaiter(this, void 0, void 0, function* () { const res = yield axiosBuilder .getInstance(baseUrl$2) .get(`${api$1}?${year && `year=${year}`}&${month && `month=${month}`}`); return res.data; }); } function create$1(model) { return __awaiter(this, void 0, void 0, function* () { const res = yield axiosBuilder.getInstance(baseUrl$2).post(`${api$1}`, model); return res.data; }); } function update(id, model) { return __awaiter(this, void 0, void 0, function* () { const res = yield axiosBuilder .getInstance(baseUrl$2) .put(`${api$1}/${id}`, model); return res.data; }); } function remove$1(id) { return __awaiter(this, void 0, void 0, function* () { const res = yield axiosBuilder.getInstance(baseUrl$2).delete(`${api$1}/${id}`); return res.data; }); } const holidayService = { getAll: getAll$1, create: create$1, update, remove: remove$1, }; const dataColumn = [ { id: "name", label: "Tiêu đề", numeric: false, sortable: false }, { id: "description", label: "Mô tả", numeric: false, sortable: false }, { id: "standardDate", label: "Ngày", numeric: false, sortable: true, }, { id: "action", label: "", numeric: false, sortable: false }, ]; function Holidays() { const { setStatus, showAlert } = React.useContext(AppContext); const [open, setOpen] = React.useState(false); const [edit, setEdit] = React.useState({ name: "", standardDate: "", description: "", }); const [data, setData] = React.useState([]); const [month, setMonth] = React.useState(new Date().getMonth() + 1); const [year, setYear] = React.useState(new Date().getFullYear()); const handleClose = () => setOpen(false); const handlePlus = () => { if (month === 12) { setMonth(1); setYear(year + 1); } else { setMonth(month + 1); } }; const handleMinus = () => { if (month === 1) { setMonth(12); setYear(year - 1); } else { setMonth(month - 1); } }; const handleSubmit = () => __awaiter(this, void 0, void 0, function* () { try { setOpen(false); if (edit.id !== undefined && edit !== null) { yield holidayService.update(edit.id, { name: edit.name, standardDate: edit.standardDate, description: edit.description, }); } else { yield holidayService.create({ name: edit.name, standardDate: edit.standardDate, description: edit.description, }); } setEdit({ id: undefined, name: "", standardDate: "", description: "", }); refresh(year, month); } catch (error) { console.log(error); } }); const handleRemove = (id) => __awaiter(this, void 0, void 0, function* () { try { yield holidayService.remove(id); refresh(year, month); } catch (error) { console.log(error); } }); const renderData = (data) => { return data.map((item) => { const row = Object.assign(Object.assign({}, item), { action: (jsxs(Fragment, { children: [jsx(IconButton, { icon: "pen", text: "S\u1EEDa", tooltip: "Edit", color: "primary", variant: "text", onClick: () => { setOpen(true); setEdit(item); } }, void 0), jsx(IconButton, { icon: "trash", text: "Xo\u00E1", tooltip: "Delete", color: "danger", variant: "text", onClick: () => handleRemove(item.id) }, void 0)] }, void 0)) }); return row; }); }; const actions = [ jsxs(Grid, Object.assign({ item: true, xs: 12, style: { padding: "16px", display: "flex", flexDirection: "row", alignItems: "center", } }, { children: [jsx(IconButton, { icon: "chevron-left", onClick: handleMinus }, void 0), jsx(Typography, Object.assign({ variant: "subtitle2" }, { children: `${month}/${year}` }), void 0), jsx(IconButton, { icon: "chevron-right", onClick: handlePlus }, void 0)] }), "action"), jsx(Grid, Object.assign({ item: true, xs: 12, style: { padding: "16px", display: "flex", flexDirection: "row", alignItems: "center", } }, { children: jsx(IconButton, { icon: "plus", variant: "text", text: "Th\u00EAm", onClick: () => { setOpen(true); setEdit({ id: undefined, name: "", standardDate: format$1.formatDate(new Date(), "yyyy-MM-dd"), description: "", }); } }, void 0) }), "create"), ]; const refresh = (year, month) => __awaiter(this, void 0, void 0, function* () { setStatus(true, "Đang tải dữ liệu ..."); try { setData(yield holidayService.getAll(year, month)); } catch (error) { showAlert("error", "Tải dữ liệu thất bại! Vui lòng thử lại sau hoặc kiểm tra kết nối mạng."); } finally { setStatus(false, ""); } }); React.useEffect(() => { refresh(year, month); }, [year, month]); return (jsxs(Fragment, { children: [jsx(FormDialog, Object.assign({ title: "Th\u00EAm/s\u1EEDa ng\u00E0y ngh\u1EC9", open: open, onClose: handleClose, onSubmit: handleSubmit }, { children: jsxs(Grid, Object.assign({ container: true, spacing: 1 }, { children: [jsx(Grid, Object.assign({ item: true, xs: 12 }, { children: jsx(TextField, { label: "Ti\u00EAu \u0111\u1EC1", value: edit.name, onChange: (e) => setEdit(Object.assign(Object.assign({}, edit), { name: e.target.value })) }, void 0) }), void 0), jsx(Grid, Object.assign({ item: true, xs: 12 }, { children: jsx(TextField, { label: "M\u00F4 t\u1EA3", value: edit.description, onChange: (e) => setEdit(Object.assign(Object.assign({}, edit), { description: e.target.value })) }, void 0) }), void 0), jsx(Grid, Object.assign({ item: true, xs: 12 }, { children: jsx(DateInput, { format: "YYYY-MM-DD", value: edit.standardDate, onChange: (v) => setEdit(Object.assign(Object.assign({}, edit), { standardDate: v })) }, void 0) }), void 0)] }), void 0) }), void 0), jsx(DataTable, { actions: actions, columns: dataColumn, data: renderData(data), title: "Ng\u00E0y ngh\u1EC9", initialOrderBy: "standardDate" }, void 0)] }, void 0)); } const checkPermission$4 = () => userService.checkModRolePermission(); const ModRole$1 = { id: 0, text: "Admin", path: "admin", order: 999, links: [ { icon: "database", text: "Dữ liệu chấm công", path: "tas/admin/transactions", color: "success", }, { icon: "users", text: "Quản lý", path: "tas/admin/managers", color: "primary", }, { icon: "users", text: "Nhân viên", path: "tas/admin/employees", color: "primary", }, { icon: "file-excel", text: "Upload dữ liệu nghỉ phép", path: "tas/admin/upload-quota", color: "warning", }, { icon: "download", text: "Báo cáo vắng mặt", path: "tas/admin/download", color: "info", }, { icon: "calendar-check", text: "Ngày nghỉ", path: "tas/admin/holidays", color: "success", }, ], pages: [ { path: "transactions", content: jsx(Transactions, {}, void 0), }, { path: "managers", content: jsx(Managers, {}, void 0), }, { path: "employees", content: jsx(Employees, {}, void 0), }, { path: "upload-quota", content: jsx(UploadQuota, {}, void 0), }, { path: "download", content: jsx(Download, {}, void 0), }, { path: "holidays", content: jsx(Holidays, {}, void 0), }, ], checkPermission: checkPermission$4, }; const baseUrl$1 = `${process.env.REACT_APP_API_HOSTNAME}`; const api = "api/v1/tas/leave-requests"; const PAID_URI = "paid"; const COMPENSATORY_URI = "compensatory"; const EVENT_URI = "event"; const NON_PAID_URI = "non-paid"; const MATERNITY_URI = "maternity"; const LATE_URI = "late"; const EARLY_URI = "early"; const TRAVEL_URI = "travel"; const SICK_URI = "sick"; const FORGET_URI = "forget"; const PAID_LEAVE = "Nghỉ phép"; const COMPENSATORY_LEAVE = "Nghỉ bù"; // const EVENT_LEAVE = "Nghỉ có lý do (hiếu/hỉ/du lịch công ty/đào tạo)"; const EVENT_LEAVE = "Nghỉ có lý do (Hiếu/Hỉ/Du lịch công ty)"; const NON_PAID_LEAVE = "Nghỉ không lương"; const MATERNITY_LEAVE = "Nghỉ thai sản"; const LATE_LEAVE = "Đi muộn"; const EARLY_LEAVE = "Về sớm"; const TRAVEL_LEAVE = "Công tác"; const SICK_LEAVE = "Nghỉ ốm"; const FORGET_LEAVE = "Quên chấm công"; const leaveRequestTypes = [ { uri: "select", description: "---Chọn loại đăng ký vắng mặt---", }, { uri: PAID_URI, description: PAID_LEAVE, }, { uri: COMPENSATORY_URI, description: COMPENSATORY_LEAVE, }, { uri: EVENT_URI, description: EVENT_LEAVE, }, { uri: NON_PAID_URI, description: NON_PAID_LEAVE, }, { uri: MATERNITY_URI, description: MATERNITY_LEAVE, }, { uri: LATE_URI, description: LATE_LEAVE, }, { uri: EARLY_URI, description: EARLY_LEAVE, }, { uri: TRAVEL_URI, description: TRAVEL_LEAVE, }, { uri: SICK_URI, description: SICK_LEAVE, }, { uri: FORGET_URI, description: FORGET_LEAVE, }, ]; function getAll() { return axiosBuilder .getInstance(baseUrl$1) .get(`${api}/items/me`) .then((res) => res.data); } function getPeriod(year, month) { return axiosBuilder .getInstance(baseUrl$1) .get(`${api}/items/me/by-period/${year}/${month}`) .then((res) => res.data); } function getByChecker() { return axiosBuilder .getInstance(baseUrl$1) .get(`${api}/items/by-checker`) .then((res) => res.data); } function getByApprover() { return axiosBuilder .getInstance(baseUrl$1) .get(`${api}/items/by-approver`) .then((res) => res.data); } function getByCheckerOrApprover() { return axiosBuilder .getInstance(baseUrl$1) .get(`${api}/items/by-checker-or-approver`) .then((res) => res.data); } function getPeriodByCheckerOrApprover(year, month) { return axiosBuilder .getInstance(baseUrl$1) .get(`${api}/items/by-checker-or-approver/by-period/${year}/${month}`) .then((res) => res.data); } function create(model, requestType) { return axiosBuilder .getInstance(baseUrl$1) .post(`${api}/items/me?request_type=${requestType}`, model); } function check(id) { return axiosBuilder.getInstance(baseUrl$1).put(`${api}/items/${id}/check`); } function approve(id) { return axiosBuilder.getInstance(baseUrl$1).put(`${api}/items/${id}/approve`); } function reject(id) { return axiosBuilder.getInstance(baseUrl$1).put(`${api}/items/${id}/reject`); } function remove(id) { return axiosBuilder.getInstance(baseUrl$1).delete(`${api}/${id}`); } function checkAccept(id) { return axiosBuilder .getInstance(baseUrl$1) .put(`${api}/items/${id}/check-accept`); } function checkReject(id) { return axiosBuilder .getInstance(baseUrl$1) .put(`${api}/items/${id}/check-reject`); } function approvalAccept(id) { return axiosBuilder .getInstance(baseUrl$1) .put(`${api}/items/${id}/approval-accept`); } function approvalReject(id) { return axiosBuilder .getInstance(baseUrl$1) .put(`${api}/items/${id}/approval-reject`); } const requestService = { getAll, getByChecker, getByApprover, create, check, approve, reject, remove, getByCheckerOrApprover, checkAccept, checkReject, approvalAccept, approvalReject, getPeriod, getPeriodByCheckerOrApprover, }; function LeaveRequestCondition({ type }) { const getCondition = (type) => { switch (type) { case "paid": return (jsxs("div", { children: [jsx(Typography, Object.assign({ variant: "body2" }, { children: "- Y\u00EAu c\u1EA7u nh\u00E2n vi\u00EAn ch\u00EDnh th\u1EE9c" }), void 0), jsx(Typography, Object.assign({ variant: "body2" }, { children: "- C\u00F2n quota ngh\u1EC9 ph\u00E9p" }), void 0)] }, void 0)); case "late": return (jsxs("div", { children: [jsx(Typography, Object.assign({ variant: "body2" }, { children: "- Kh\u00F4ng \u00E1p d\u1EE5ng gi\u1EDD linh ho\u1EA1t cho ng\u00E0y th\u1EE9 7 v\u00E0 bu\u1ED5i chi\u1EC1u c\u00E1c ng\u00E0y trong tu\u1EA7n" }), void 0), jsx(Typography, Object.assign({ variant: "body2" }, { children: "- \u0110i mu\u1ED9n/V\u1EC1 s\u1EDBm t\u1ED1i \u0111a 3 l\u1EA7n/th\u00E1ng" }), void 0)] }, void 0)); case "early": return (jsx("div", { children: jsx(Typography, Object.assign({ variant: "body2" }, { children: "- \u0110i mu\u1ED9n/V\u1EC1 s\u1EDBm t\u1ED1i \u0111a 3 l\u1EA7n/th\u00E1ng" }), void 0) }, void 0)); case "travel": return (jsx("div", { children: jsx(Typography, Object.assign({ variant: "body2" }, { children: "- Th\u1EDDi gian c\u00F4ng t\u00E1c l\u1EDBn h\u01A1n 2 gi\u1EDD" }), void 0) }, void 0)); default: return (jsx("div", { children: jsx(Typography, Object.assign({ variant: "body2" }, { children: "- Kh\u00F4ng y\u00EAu c\u1EA7u \u0111i\u1EC1u ki\u1EC7n" }), void 0) }, void 0)); } }; return getCondition(type); } const TimeRequestOptions = [ { time: 0, name: "---Chọn thời gian vắng mặt---", }, { time: 30, name: "Từ 01 đến 30 (phút)", }, { time: 60, name: "Từ 31 đến 60 (phút)", }, { time: 120, name: "Từ 61 đến 120 (phút)", }, { time: 180, name: "Từ 121 đến 180 (phút)", }, ]; const SessionOfDay = [ { type: "AM", name: "Buổi sáng" }, { type: "PM", name: "Buổi chiều" }, ]; const CalEndTimeLateLeave = (session, time) => { if (session === "AM") { if (time === 30) return "09:30"; if (time === 60) return "10:00"; if (time === 90) return "10:30"; if (time === 120) return "11:00"; } else { if (time === 30) return "13:30"; if (time === 60) return "14:00"; if (time === 90) return "14:30"; if (time === 120) return "15:00"; } return ""; }; const CalTimeEarlyLeave = (session, time) => { if (session === "AM") { if (time === 30) return "11:30"; if (time === 60) return "11:00"; } else { if (time === 30) return "17:30"; if (time === 60) return "17:00"; if (time === 90) return "16:30"; if (time === 120) return "16:00"; if (time === 180) return "15:00"; } return ""; }; const RenderTimeWithType = (start, end, leaveType) => { const type = leaveRequestTypes[leaveType].uri; const startTime = format$1.formatDate(new Date(start), "hh:mm"); const endTime = format$1.formatDate(new Date(end), "hh:mm"); if (type === "early") { if (startTime === "17:30") return { start: "Từ 0 phút", end: "đến 30 phút", }; if (startTime == "17:00") return { start: "Từ 30 phút", end: "đến 60 phút", }; if (startTime == "16:00") return { start: "Từ 60 phút", end: "đến 120 phút", }; } return { start: startTime, end: endTime, }; }; const renderSessionOptionsOfDay = (type) => { const AllSessionOption = { type: "ALL", name: "Cả ngày", }; const OtherOption = { type: "OTHER", name: "Khung giờ khác", }; if (type === PAID_URI || type === NON_PAID_URI) return [...SessionOfDay, AllSessionOption]; if (type === FORGET_URI) return [ { type: "AM", name: "Giờ vào" }, { type: "PM", name: "Giờ ra" }, AllSessionOption, ]; if (type === EARLY_URI) return [...SessionOfDay, OtherOption]; if (type === TRAVEL_URI) return [...SessionOfDay, AllSessionOption, OtherOption]; if (type === LATE_URI) return [...SessionOfDay, OtherOption]; if (type === COMPENSATORY_URI) return [AllSessionOption, ...SessionOfDay]; return SessionOfDay; }; const renderTimeRequestOption = (type, session) => { if (session) { if (session.type === "AM") { if (type === LATE_URI || type === EARLY_URI) return TimeRequestOptions.filter((x) => x.time < 90); } if (session.type === "PM") { if (type === LATE_URI || type === EARLY_URI) return TimeRequestOptions.filter((x) => x.time < 180); } } return TimeRequestOptions; }; const checkOpenSessionOptions = (type) => type === PAID_URI || type === NON_PAID_URI || type === LATE_URI || type === EARLY_URI || type === TRAVEL_URI || type === FORGET_URI || type === COMPENSATORY_URI; const checkOpenTimeOptions = (type, session) => (session === null || session === void 0 ? void 0 : session.type) !== "OTHER" && (type === LATE_URI || type === EARLY_URI); const checkOpenTimeInput = (time, session) => (time === null || time === void 0 ? void 0 : time.time) === 0 || (session === null || session === void 0 ? void 0 : session.type) === "OTHER"; function ConditionRequest({ requestDate, type, inTime, outTime, startTime, endTime, note, onChangeStart, onChangeEnd, onChangeNote, }) { const [session, setSession] = useState(null); const [time, setTime] = useState(null); React.useEffect(() => { setSession(null); setTime(null); }, [requestDate]); useEffect(() => { switch (type) { case PAID_URI: case NON_PAID_URI: if (session && requestDate.getDay() === 6) { onChangeStart("08:00"); onChangeEnd("12:00"); } if (session && requestDate.getDay() !== 6) { if (session.type === "AM") { onChangeStart("08:00"); onChangeEnd("12:00"); } if (session.type === "PM") { console.log("PM session"); onChangeStart("13:00"); onChangeEnd("