Untitled
unknown
plain_text
5 months ago
19 kB
2
Indexable
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 'modules/mdSauDaiHoc/sdhConfigHocPhan/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.props.getSdhConfigHocPhanDssv(this.props.maHocPhan, '', listStudent => this.setState({ listStudent, dataConfigHocPhan, dataConfigMonHoc, maMonHoc, maHocPhan }, () => { listStudent.forEach(item => { this.diemTk[item.mssv]?.value(item.tongKet); }); })); }); } 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(); if (parseFloat(value) < 0 || parseFloat(value) > 10) { e.target.innerText = diem ? diem : ''; T.notify('Điểm phải nằm trong khoảng 0 - 10!', 'warning'); return; } else if (parseFloat(value) >= 0 || parseFloat(value) <= 10 || value == '') { this.state.listStudent.map(item => { if (item.mssv == mssv) { item.diemThanhPhan.map(i => { if (i.maLoaiDiem == maLoaiDiem) { i.diemNew = value; i.phanTram = dataConfigHocPhan.find(e => e.maLoaiDiem == maLoaiDiem).phanTram; } }); } }); } // Update diem tong ket let sum = ''; for (const tp of dataConfigHocPhan) { const objectDiemTp = student.diemThanhPhan.find(e => e.maLoaiDiem == tp.maLoaiDiem); const diemTp = objectDiemTp.diemNew ?? objectDiemTp.diem; if (diemTp && isNaN(diemTp)) { sum = diemTp; break; } else if (diemTp != '' && diemTp != null) { if (sum == '') sum = parseFloat(diemTp) * parseInt(tp.phanTram ?? 0); else sum += parseFloat(diemTp) * parseInt(tp.phanTram); } } if (!isNaN(parseFloat(sum))) { sum = (Math.round((sum / 100) * 10) / 10).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; } } else if (/[0-9',']/.test(key)) { // Prevent commas e.preventDefault(); return; } } if (key !== 'Backspace' && key !== 'Delete') { value += key; } 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(); } } } } } handleHuyNhapDiem = (e) => { e.preventDefault(); let { listStudent } = this.state; listStudent.forEach(item => { this.diemTk[item.mssv].value(item.tongKet); }); this.setState({ isNhapDiem: false }); } handleGhiChu = (value, mssv) => { this.ghiChu[mssv].value(value); } save = () => { const dataStudent = []; const { listStudent } = this.state; listStudent.map(item => { item.diemThanhPhan.map(i => { const data = { oldId: i.id, mssv: item.mssv, loaiDiem: i.maLoaiDiem, diemNew: i.diemNew, phamTramDiem: i.phanTram, diem: i.diem }; if (i.diemNew && i.diemNew != i.diem) dataStudent.push(data); }); const diemTongKet = this.diemTk[item.mssv]?.value() ?? ''; item.tongKet != diemTongKet && dataStudent.push({ oldId: item.idDiemTongKet, mssv: item.mssv, loaiDiem: 'TK', diem: item.tongKet, diemNew: diemTongKet }); }); const dataHocPhan = { maHocPhan: this.state.maHocPhan, maMonHoc: this.state.maMonHoc, namHoc: this.props.namHoc, hocKy: this.props.hocKy }; 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) { if (dataStudent.length == 0) { T.alert('Cập nhập điểm thành công!', 'success', false, 500); this.setState({ isNhapDiem: false }); this.props.resetPage(); } else { 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); this.setState({ isNhapDiem: false }); this.props.resetPage(); }); } } }); } render() { let { listStudent, dataConfigHocPhan, dataConfigMonHoc, dataConfigQuyChe, isNhapDiem, readOnly, maMonHoc, maHocPhan } = this.state; const { namHoc, hocKy } = this.props; let widthTP = 40 / (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']); const conditionCauHinhDiemHp = dataConfigHocPhan.length; // && !dataConfigHocPhan.find(item => !item.phanTram); 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: '10%', verticalAlign: 'middle' }}>MSSV</th> <th style={{ width: '20%', verticalAlign: 'middle' }}>Họ và tên lót</th> <th style={{ width: '10%', verticalAlign: 'middle' }}>Tên</th> <th style={{ width: '20%', 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: '30%', 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={item.mssv}> <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, timeMod = item.diemThanhPhan.find(e => e.maLoaiDiem == loaiThanhPhan)?.timeModified, userMod = item.diemThanhPhan.find(e => e.maLoaiDiem == loaiThanhPhan)?.userModified, title = userMod ? `${T.dateToText(Number(timeMod), 'dd/mm/yyyy HH:MM:ss')} - ${userMod}` : '', diem = item.diemThanhPhan.find(e => e.maLoaiDiem == loaiThanhPhan)?.diem ?? '', loaiLamTron = item.diemThanhPhan.find(e => e.maLoaiDiem == loaiThanhPhan)?.loaiLamTron ?? 0; const rate = parseFloat(loaiLamTron) / 0.1; let diemLamTron; if (!rate) { diemLamTron = diem ?? ''; } else { diemLamTron = diem ? Math.round(diem * (10 / rate)) / (10 / rate).toFixed(1).toString() : ''; } return isNhapDiem ? <Tooltip arrow placement='top' 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' }} > {diem} </div> </td> </Tooltip> : <Tooltip arrow placement='top' title={title}> <td><div style={{ whiteSpace: 'nowrap', textAlign: 'center' }}>{diemLamTron}</div></td> </Tooltip>; })} <TableCell key={item.mssv} 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 => this.handleHuyNhapDiem(e)}> <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: !dataConfigHocPhan.length || !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 { this.setState({ isNhapDiem: true }); } } }}> <i className={'fa fa-lg ' + icon} /> {isNhapDiem ? 'Lưu' : 'Nhập điểm'} </button> </Tooltip> </React.Fragment> </div> </div> </div> <div className='m-4'> {conditionCauHinhDiemHp ? studentTable : ''} </div> <EditCauHinhHocPhan resetPage={this.props.resetPage} ref={e => this.modal = e} dataConfigHocPhan={dataConfigHocPhan} maMonHoc={maMonHoc} maHocPhan={maHocPhan} namHoc={namHoc} hocKy={hocKy} setData={this.setData} /> </>); } } const mapStateToProps = state => ({ system: state.system }); const mapActionsToProps = { getSdhConfigDiemByHocPhan, getSdhConfigHocPhanDssv, storeDiemHocVienByHocPhan }; export default connect(mapStateToProps, mapActionsToProps, null, { forwardRef: true })(SectionHocPhanSinhVien);
Editor is loading...
Leave a Comment