Untitled
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