Untitled

mail@pastecode.io avatar
unknown
plain_text
7 days ago
18 kB
2
Indexable
Never
import React from 'react';
import { AdminPage, renderDataTable, TableCell, FormTextBox } from 'view/component/AdminPage';
import { getSdhConfigDiemByHocPhan } from 'modules/mdSauDaiHoc/sdhConfigHocPhan/redux';
import { connect } from 'react-redux';
import { Tooltip } from '@mui/material';
import EditCauHinhHocPhan from 'modules/mdSauDaiHoc/sdhConfigHocPhan/section/edit-cau-hinh-hoc-phan';
import { getSdhConfigHocPhanDssv, storeDiemHocVienByHocPhan } from '../redux';
import { getSdhDiemConfigQuyCheAll } from 'modules/mdSauDaiHoc/sdhDiemConfigQuyChe/redux';
class SectionHocPhanSinhVien extends AdminPage {
    defaultSortTerm = 'mssv_ASC'

    diemTk = {}
    ghiChu = {}

    thanhPhanDiem = {}

    state = { filter: {}, dataConfigMonHoc: [], dataConfigHocPhan: [], dataConfigQuyChe: [], listStudent: [], maMonHoc: '', maHocPhan: '' }

    setData = (data) => {
        let { maMonHoc, maHocPhan } = data;
        this.props.getSdhConfigDiemByHocPhan({ maMonHoc, maHocPhan }, dataState => {
            let { dataConfigHocPhan = [], dataConfigMonHoc = [] } = dataState;
            this.setState({ dataConfigHocPhan, dataConfigMonHoc, maMonHoc, maHocPhan });
        });
        this.props.getSdhConfigHocPhanDssv(this.props.maHocPhan, '', listStudent => this.setState({ listStudent }));
    }


    handleDiem = (e, student, thanhPhan) => {
        let { maLoaiDiem } = thanhPhan,
            { mssv } = student,
            diem = student.diemThanhPhan.find(e => e.maLoaiDiem == maLoaiDiem)?.diem,
            { dataConfigHocPhan } = this.state,
            value = e.target.innerText?.toUpperCase(),
            invalidValue = (diem && diem[mssv + maLoaiDiem]) || '',
            loaiLamTron = 0.1;

        console.log('value: ', value);

        if (parseFloat(value) < 0 || parseFloat(value) > 10) {
            e.target.innerText = invalidValue;
            T.notify('Điểm phải nằm trong khoảng 0 - 10!', 'warning');
            return;
        } else if (parseFloat(value) >= 0 || parseFloat(value) <= 10) {
            const rate = parseFloat(loaiLamTron) / 0.1;
            value = Math.round(value * (10 / rate)) / (10 / rate);
            value = value.toFixed(1).toString();
            student.diemThanhPhan.find(e => e.maLoaiDiem == maLoaiDiem).diem = value;

            this.state.listStudent.map(item => {
                if (item.mssv == mssv) {
                    item.diemThanhPhan.map(i => {
                        if (i.maLoaiDiem == maLoaiDiem) {
                            if (diem && diem != value) {
                                i.diemOld = diem;
                                i.diemNew = value;
                            }
                            else {
                                i.diemOld = '';
                                i.diemNew = value;
                            }

                            i.phanTram = dataConfigHocPhan.find(e => e.maLoaiDiem == maLoaiDiem).phanTram;
                        }
                    });
                }
            });
        }
        // Update diem tong ket
        let sum = '';
        for (const tp of dataConfigHocPhan) {
            const diemTp = student.diemThanhPhan.find(e => e.maLoaiDiem == tp.maLoaiDiem)?.diem;
            if (diemTp && isNaN(diemTp)) {
                sum = diemTp;
                break;
            } else if (diemTp != '' && diemTp != null) {
                if (sum == '') sum = parseFloat(diemTp) * parseInt(tp.phanTram);
                else sum += parseFloat(diemTp) * parseInt(tp.phanTram);
            }
        }

        if (!isNaN(parseFloat(sum))) {
            sum = (Math.round((2 * sum) / 100) / 2).toFixed(1);
        }

        this.diemTk[mssv].value(sum.toString());
    }

    handlePressDiem = (e) => {
        let key = e.key,
            value = e.target.textContent;

        // Only allow numeric values, decimal point, and backspace/delete keys
        const allowKeys = ['Backspace', 'Delete', 'Enter', 'ArrowUp', 'ArrowDown', 'ArrowRight', 'ArrowLeft', 'Tab'];

        if (!allowKeys.includes(key)) {
            if (/[0-9\.]/.test(key)) {
                // Only allow one decimal point
                if (key === '.' && value.includes('.')) {
                    e.preventDefault();
                    return;
                }

                // Limit value between 0 and 10
                if (parseFloat(value) < 0 || parseFloat(value) > 10) {
                    e.preventDefault();
                }
            }
        }

        if (key !== 'Backspace' && key !== 'Delete') {
            value += key;
        }

        // Limit value between 0 and 10
        if (parseFloat(value) < 0 || parseFloat(value) > 10) {
            e.preventDefault();
            return;
        }

        if (key == 'ArrowDown') {
            const currentTd = e.target.parentElement;
            const nextTd = currentTd.parentNode.nextElementSibling?.querySelector(`td:nth-child(${currentTd.cellIndex + 1})`);
            if (nextTd) {
                currentTd.children[0].blur();
                nextTd.children[0].focus();
            }
        }

        if (key == 'ArrowUp') {
            const currentTd = e.target.parentElement;
            const prevTd = currentTd.parentNode.previousElementSibling?.querySelector(`td:nth-child(${currentTd.cellIndex + 1})`);
            if (prevTd) {
                currentTd.children[0].blur();
                prevTd.children[0].focus();
            }
        }

        if (key == 'ArrowRight' || key === 'Enter' || key == 'NumpadEnter' || key === 'Tab') {
            e.preventDefault();
            const currentTd = e.target.parentElement;
            const nextTd = currentTd.nextElementSibling;
            currentTd.children[0].blur();
            if (nextTd && nextTd.children[0].id != '') {
                nextTd.children[0].focus();
            } else {
                const nextTr = currentTd.parentElement.nextElementSibling;
                if (nextTr) {
                    const nextTd = nextTr.querySelector('td:nth-child(6)');
                    if (nextTd) {
                        currentTd.children[0].blur();
                        nextTd.children[0].focus();
                    }
                }
            }

        }

        if (key == 'ArrowLeft') {
            const currentTd = e.target.parentElement;
            const prevTd = currentTd.previousElementSibling;
            if (prevTd && prevTd.children[0].id != '') {
                currentTd.children[0].blur();
                prevTd.children[0].focus();
            } else {
                const prevTr = currentTd.parentElement.previousElementSibling;
                if (prevTr) {
                    const prevTd = prevTr.querySelector(`td:nth-child(${6 + this.state.dataConfigHocPhan.length - 1})`);
                    if (prevTd) {
                        currentTd.children[0].blur();
                        prevTd.children[0].focus();
                    }
                }
            }
        }
    }

    handleGhiChu = (value, mssv) => {
        this.ghiChu[mssv].value(value);
    }

    save = () => {
        const dataStudent = [];
        const { listStudent } = this.state;
        let canPush = true;
        listStudent.map(item => {
            item.diemThanhPhan.map(i => {
                const data = {
                    mssv: item.mssv,
                    loaiDiem: i.maLoaiDiem,
                    diemOld: i.diemOld,
                    diemNew: i.diemNew,
                    phanTram: i.phanTram
                };
                if (i.diemNew) dataStudent.push(data);
                else canPush = false;
            });
            if (canPush) {
                dataStudent.push({
                    mssv: item.mssv,
                    loaiDiem: 'TK',
                    diem: this.diemTk[item.mssv]?.value()
                });
            }

        });

        console.log('dataStudent: ', dataStudent);
        const dataHocPhan = {
            maHocPhan: this.state.maHocPhan,
            maMonHoc: this.state.maMonHoc,
            namHoc: this.props.namHoc,
            hocKy: this.props.hocKy
        };
        console.log('datahocphan: ', dataHocPhan);

        T.confirm('Cảnh báo', 'Bạn có chắc chắn muốn Cập nhật điểm của lớp học phần này không?', 'warning', true, isConfirm => {
            if (isConfirm) {
                T.alert('Đang cập nhật điểm sinh viên!', 'warning', false, null, true);
                this.props.storeDiemHocVienByHocPhan(dataHocPhan, dataStudent, () => T.alert('Cập nhập điểm thành công!', 'success', false, 500));
            }
        });
    }

    render() {
        let { listStudent, dataConfigHocPhan, dataConfigMonHoc, dataConfigQuyChe, isNhapDiem, readOnly, tinhTrangDiem, maMonHoc, maHocPhan } = this.state;

        let widthTP = 30 / (dataConfigHocPhan.length + 1);
        const { isManage } = this.props,
            className = isNhapDiem ? 'btn btn-success' : 'btn btn-primary',
            icon = isNhapDiem ? 'fa-save' : 'fa-pencil',
            textButton = isNhapDiem ? 'Lưu' : 'Nhập điểm',
            viewing = this.props.viewing;

        const permission = this.getUserPermission('sdhConfigHocPhan', ['read', 'write', 'delete']);

        console.log('list student', listStudent);

        let studentTable = renderDataTable({
            emptyTable: 'Không có dữ liệu học viên',
            stickyHead: false,
            header: 'thead-light',
            loadingStyle: { backgroundColor: 'white' },
            data: listStudent,
            renderHead: () => {
                return (<>
                    <tr>
                        <th style={{ width: 'auto', verticalAlign: 'middle' }}>#</th>
                        <th style={{ width: 'auto', verticalAlign: 'middle' }}>MSSV</th>
                        <th style={{ width: '30%', verticalAlign: 'middle' }}>Họ và tên lót</th>
                        <th style={{ width: '10%', verticalAlign: 'middle' }}>Tên</th>
                        <th style={{ width: '10%', verticalAlign: 'middle' }}>Lớp</th>
                        {dataConfigHocPhan.map((item, index) => (<th key={index} style={{ width: `${widthTP}%`, whiteSpace: 'nowrap', textAlign: 'center' }}>{item.tenLoaiDiem}</th>))}
                        <th style={{ width: 'auto', whiteSpace: 'nowrap', textAlign: 'center' }}>Điểm tổng kết</th>
                        <th style={{ width: '50%', whiteSpace: 'nowrap', textAlign: 'center' }}>Ghi chú</th>
                    </tr>
                </>
                );
            },
            renderRow: (item, index) => {
                return (
                    <tr key={`student-${index}`}>
                        <TableCell content={index + 1} />
                        <TableCell content={item.mssv} />
                        <TableCell content={item.ho} />
                        <TableCell content={item.ten} />
                        <TableCell style={{ whiteSpace: 'nowrap' }} content={item.lop} />
                        {listStudent.length && dataConfigHocPhan.map(thanhPhan => {
                            let loaiThanhPhan = thanhPhan.maLoaiDiem;

                            let diem = item.diemThanhPhan.find(e => e.maLoaiDiem == loaiThanhPhan)?.diem;

                            let title = '';
                            diem = (!isNaN(parseFloat(diem))) ? parseFloat(diem).toFixed(1).toString() : diem;
                            return isNhapDiem ? <Tooltip arrow title={title}>
                                <td>
                                    <div key={`${item.mssv}_${loaiThanhPhan}`} id={`${item.mssv}_${loaiThanhPhan}`}
                                        contentEditable suppressContentEditableWarning={true}
                                        onBlur={e => this.handleDiem(e, item, thanhPhan)}
                                        onKeyDown={e => this.handlePressDiem(e, thanhPhan)}
                                        style={{ whiteSpace: 'nowrap', verticalAlign: 'middle', textAlign: 'center', cursor: 'auto', border: '1.5px solid #ced4da', borderCollapse: 'collapse', borderRadius: '4px', fontSize: 'large', fontFamily: 'serif' }}
                                    >
                                        {diem}
                                    </div>
                                </td>
                            </Tooltip> : <Tooltip arrow title={title}>
                                <td><div style={{ whiteSpace: 'nowrap', textAlign: 'center' }}>{diem}</div></td>
                            </Tooltip>;
                        })}
                        <TableCell style={{ width: 'auto', textAlign: 'center', justifyContent: 'center' }} content={<FormTextBox className='mb-0' ref={e => this.diemTk[item.mssv] = e} readOnly />} />
                        <TableCell style={{ width: 'auto', justifyContent: 'center' }} content={<FormTextBox className='mb-0' placeholder='Ghi chú' ref={e => this.ghiChu[item.mssv] = e} readOnly={readOnly || !isNhapDiem} onBlur={(e) => this.handleGhiChu(e, item.mssv)} />} />
                    </tr>
                );
            }
        });

        return (<>

            <div style={{ textAlign: 'left', margin: '10px 24px 10px 24px' }}>
                <hr />
                <div className='row' style={{ fontSize: '0.8rem' }}>
                    <div className='col-md-6' style={{ display: dataConfigQuyChe.length ? '' : 'none' }}>
                        <h6>Thông tin các điểm đặc biệt: </h6>
                        {<div className='d-flex flex-wrap' style={{ padding: 'inherit' }}>
                            {dataConfigQuyChe.map((item, index) => {
                                return <span key={`qc-${index}`} style={{ marginRight: 'auto', whiteSpace: 'nowrap' }}>- <b>{item.ma}</b>: {item.moTa} </span>;
                            })}
                        </div>}
                    </div>

                    <div className='col-md-6' style={{ display: dataConfigHocPhan.length ? '' : 'none' }}>
                        <h6>Thông tin các điểm thành phần: </h6>
                        {<div className='d-flex flex-wrap' style={{ padding: 'inherit' }}>
                            {dataConfigHocPhan.map((item, index) => {
                                return <span key={`tp-${index}`} style={{ marginRight: 'auto', whiteSpace: 'nowrap' }}>- <b>{item.tenLoaiDiem} ({item.maLoaiDiem})</b>: {item.phanTram}% (từ {item.phanTramMin}% - {item.phanTramMax}%) </span>;
                            })}
                        </div>}
                    </div>
                </div>

                <div className='row'>
                    <div className='col-md-12' style={{ display: 'flex', flexDirection: 'row-reverse', gap: 10, marginTop: '10px' }}>
                        <React.Fragment>
                            <Tooltip title='Cấu hình phần trăm điểm' arrow placement='top'>
                                <button className='btn btn-success' type='button' onClick={() => {
                                    this.modal.show({ dataConfigHocPhan, dataConfigMonHoc });
                                }}>
                                    <i className='fa fa-fw fa-lg fa-cogs' /> Cấu hình điểm
                                </button>
                            </Tooltip>

                            <Tooltip title='Huỷ' placement='top' arrow>
                                <button className='btn btn-secondary' style={{ display: isNhapDiem ? '' : 'none', height: 'fit-content' }}
                                    onClick={e => e.preventDefault() || this.setState({ isNhapDiem: false })}>
                                    <i className='fa fa-lg fa-times' /> Hủy
                                </button>
                            </Tooltip>
                            <Tooltip title={textButton} placement='top' arrow>
                                <button className={className} style={{ height: 'fit-content', display: !permission.write || viewing ? 'none' : '' }} onClick={e => {
                                    e.preventDefault();
                                    if (isNhapDiem) this.save();
                                    else {
                                        if (!isManage && readOnly) {
                                            T.alert('Không trong thời gian nhập điểm', 'warning', false, 5000);
                                        } else if (tinhTrangDiem == 4) {
                                            T.alert('Học phần đã khóa bảng điểm', 'warning', false, 5000);
                                        }
                                        else {
                                            this.setState({ isNhapDiem: true });
                                        }
                                    }
                                }}>
                                    <i className={'fa fa-lg ' + icon} /> Nhập điểm
                                </button>
                            </Tooltip>
                        </React.Fragment>
                    </div>
                </div>
            </div>

            <div className='m-4'>
                {studentTable}
            </div>

            <EditCauHinhHocPhan resetPage={this.props.resetPage} ref={e => this.modal = e} dataConfigHocPhan={dataConfigHocPhan} maMonHoc={maMonHoc} maHocPhan={maHocPhan} setData={this.setData} />
        </>);
    }
}


const mapStateToProps = state => ({ system: state.system });
const mapActionsToProps = {
    getSdhConfigDiemByHocPhan, getSdhConfigHocPhanDssv, getSdhDiemConfigQuyCheAll, storeDiemHocVienByHocPhan
};
export default connect(mapStateToProps, mapActionsToProps, null, { forwardRef: true })(SectionHocPhanSinhVien);
Leave a Comment