Untitled
unknown
plain_text
a year ago
18 kB
11
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 '../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);
Editor is loading...
Leave a Comment