Compare commits

...

7 Commits

  1. 4
      src/_components/Auth/InputText/index.scss
  2. 19
      src/_components/Header/header.style.scss
  3. 5
      src/_components/Header/index.js
  4. 24
      src/_components/boxChart/BoxDoughnutBarChart.js
  5. 22
      src/_components/boxChart/BoxDoughnutChar.js
  6. 50
      src/_components/boxChart/boxChart.scss
  7. 2
      src/_components/chart/RDoughnutChart.js
  8. 18
      src/_components/chart/VerticalBarChart.js
  9. 29
      src/_screens/home/detail-room-education/index.js
  10. 20
      src/_screens/home/education-department/index.js
  11. 15
      src/_screens/home/outstanding-teacher/index.js
  12. 3
      src/_screens/home/outstanding-teacher/outstandingTeacher.style.scss

@ -98,7 +98,7 @@ $border-color: #4a4848;
.icon_label { .icon_label {
width: 31px; width: 31px;
margin-right: 8px; // margin-right: 8px;
@include screen_mobile { @include screen_mobile {
margin-right: 0 !important; margin-right: 0 !important;
@ -168,4 +168,4 @@ $border-color: #4a4848;
::-ms-reveal { ::-ms-reveal {
display: none; display: none;
} }

@ -16,6 +16,25 @@
font-weight: 700; font-weight: 700;
color: #4d4d4d; color: #4d4d4d;
} }
.header-back-button {
height: 40px;
border-radius: 20px;
border: none;
font-size: 16px;
color: #fff;
font-family: 'Myriadpro-SemiBold';
background-color: var(--button-bg-color);
display: flex;
justify-content: center;
align-items: center;
min-width: 64px;
white-space: nowrap;
}
.header-back-button:hover {
background-color: #c07a05;
}
} }
.header-right-side { .header-right-side {

@ -28,12 +28,11 @@ export default function Header({ icon, title, subtitles = [], manager = false, i
<div className="header-left-side"> <div className="header-left-side">
{isBack && ( {isBack && (
<div style={{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center' }}> <div style={{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center' }}>
<PrimaryButton style={{ alignSelf: "center", justifyContent:'flex end', marginRight:30 }} onClick={()=>{ <button className="header-back-button" onClick={()=>{
history.goBack() history.goBack()
}}> }}>
<div style={{marginRight: 8, paddingBottom: 4}}>{renderIconButtonLeft()}</div> <div style={{marginRight: 8, paddingBottom: 4}}>{renderIconButtonLeft()}</div>
Quay lại </button>
</PrimaryButton>
</div> </div>
)} )}
{icon} {icon}

@ -43,11 +43,23 @@ export default function BoxDoughnutBarChart({
<div className='doughnut-chart-content flex-1'> <div className='doughnut-chart-content flex-1'>
<RDoughnutChart data={dataDoughnut} /> <RDoughnutChart data={dataDoughnut} />
</div> </div>
<div className='origin-vertical justify-content-center align-item-center flex-1'> <div className='origin-vertical justify-content-center align-item-center flex-1' style={{cursor:'pointer'}}>
<p style={{color: PRIMARY_COLOR, fontSize: '2.2rem', fontWeight: 800}}>{current}</p> <div className="tooltip">
<p style={{color: '#01AEF0', fontSize: '2.2rem', fontWeight: 800}}> <p
{target > 0 ? target : '...'} style={{color: PRIMARY_COLOR, fontSize: '2.2rem', fontWeight: 800}}
</p> >
{current}
<span className="tooltiptext" style={{color: PRIMARY_COLOR}}>Số lượng đã tham gia: {current}</span>
</p>
</div>
<div className="tooltip">
<p
style={{color: '#01AEF0', fontSize: '2.2rem', fontWeight: 800}}
>
{target > 0 ? target : '...'}
<span className="tooltiptext" style={{color: '#01AEF0'}}>Tổng số: {target > 0 ? target : '...'}</span>
</p>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -59,7 +71,7 @@ export default function BoxDoughnutBarChart({
{subTitleLine && <p className='box-chart-subtitle'>{subTitleLine}</p>} {subTitleLine && <p className='box-chart-subtitle'>{subTitleLine}</p>}
{dataBarChart.length > 0 ? ( {dataBarChart.length > 0 ? (
<div className='chart-container'> <div className='chart-container'>
<div className='flex-1' style={{ padding: '1.6rem 0', height: '100%', width: '360px' }}> <div className='flex-1' style={{ padding: '1.6rem 0', height: '100%'}}>
<VerticalBarChart data={dataBarChart} labels={labelsBarChart} /> <VerticalBarChart data={dataBarChart} labels={labelsBarChart} />
</div> </div>
</div> </div>

@ -10,15 +10,31 @@ export default function BoxDoughnutChart({data = [], title, propsContainer}) {
const renderStats = () => { const renderStats = () => {
return ( return (
<> <>
<p style={{color: PRIMARY_COLOR, fontSize: '2.2rem', fontWeight: 800}}>{current}</p> <div style={{cursor:'pointer',display: 'flex', flexDirection: 'column', alignItems:'center'}}>
<p style={{color: '#01AEF0', fontSize: '2.2rem', fontWeight: 800}}>{target > 0 ? target : '...'}</p> <div className="tooltip">
<p
style={{color: PRIMARY_COLOR, fontSize: '2.2rem', fontWeight: 800}}
>
{current}
<span className="tooltiptext" style={{color: PRIMARY_COLOR}}>Số lượng đã tham gia: {current}</span>
</p>
</div>
<div className="tooltip">
<p
style={{color: '#01AEF0', fontSize: '2.2rem', fontWeight: 800}}
>
{target > 0 ? target : '...'}
<span className="tooltiptext" style={{color: '#01AEF0'}}>Tổng số: {target > 0 ? target : '...'}</span>
</p>
</div>
</div>
</> </>
) )
} }
return ( return (
<div className="box-chart-container" {...propsContainer}> <div className="box-chart-container" {...propsContainer}>
<p className='box-chart-subtitle'>{title}</p> <p className='box-chart-subtitle' style={{ marginBottom: '1.2rem'}}>{title}</p>
<div className='d-flex flex-1'> <div className='d-flex flex-1'>
<div className='doughnut-chart-content flex-1'> <div className='doughnut-chart-content flex-1'>
<RDoughnutChart data={data} /> <RDoughnutChart data={data} />

@ -7,8 +7,12 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@media (max-width: 1750px) { @media (min-width: 1600px) and (max-width: 1750px) {
max-width: 250px; width: 300px;
}
@media (max-width: 1599px) {
max-width: 260px;
} }
.box-chart-title { .box-chart-title {
@ -23,7 +27,9 @@
font-weight: 700; font-weight: 700;
} }
.doughnut-chart-content {} // .doughnut-chart-content {
// min-width: 120px;
// }
.custom-button { .custom-button {
padding: 8px; padding: 8px;
@ -54,12 +60,40 @@
} }
.chart-container { .chart-container {
overflow-x: scroll; // overflow-x: scroll;
height: 100%; height: 100%;
width: 300px; // width: 300px;
// @media (max-width: 1750px) {
// max-width: 240px;
// }
}
}
.tooltip {
position: relative;
display: inline-block;
.tooltiptext {
visibility: hidden;
width: max-content;
background-color: #fff;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px;
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
transform: translateX(-50%);
opacity: 0;
transition: opacity 0.3s;
font-size: 1.4rem;
}
@media (max-width: 1750px) { &:hover .tooltiptext {
max-width: 220px; visibility: visible;
} opacity: 1;
} }
} }

@ -46,6 +46,8 @@ export default function RDoughnutChart({data = [], ...other}) {
return `${label}: ${value}`; return `${label}: ${value}`;
}, },
}, },
position: 'nearest',
z: 1000,
}, },
legend: false, legend: false,
} }

@ -15,7 +15,8 @@ export function VerticalBarChart({data = [], labels = []}) {
maxValue = item; maxValue = item;
} }
}) })
// labels = labels?.map((item) => item.replace('Tuần', 'W'));
labels = labels?.map(week => week.split(" "));
const options = { const options = {
responsive: true, responsive: true,
@ -24,15 +25,21 @@ export function VerticalBarChart({data = [], labels = []}) {
legend: { legend: {
display: false display: false
}, },
// title: {
// display: true,
// text: 'Tuần',
// align: 'start',
// position: 'bottom',
// },
datalabels: { datalabels: {
anchor: 'end', // Position of the labels (start, end, center, etc.) anchor: 'end',
align: 'end', // Alignment of the labels (start, end, center, etc.) align: 'end',
color: 'blue', // Color of the labels color: 'blue',
font: { font: {
weight: 'bold', weight: 'bold',
}, },
formatter: function (value, context) { formatter: function (value, context) {
return value; // Display the actual data value return value;
} }
} }
}, },
@ -40,7 +47,6 @@ export function VerticalBarChart({data = [], labels = []}) {
x: { x: {
ticks: { ticks: {
maxRotation: 0, maxRotation: 0,
// scrollX : true,
}, },
}, },
y: { y: {

@ -38,6 +38,7 @@ export default function DetailRoomEducation() {
const [isLoadingStatisticCircle, setIsLoadingStatisticCircle] = useState(false); const [isLoadingStatisticCircle, setIsLoadingStatisticCircle] = useState(false);
const [isLoadingStudentChart, setIsLoadingStudentChart] = useState(false); const [isLoadingStudentChart, setIsLoadingStudentChart] = useState(false);
const [isLoadingTeacherChart, setIsLoadingTeacherChart] = useState(false); const [isLoadingTeacherChart, setIsLoadingTeacherChart] = useState(false);
const [isFilterChanged, setIsFilterChanged] = useState(false);
const [isLoadMoreOnline, setLoadMoreOnline] = useState(true); const [isLoadMoreOnline, setLoadMoreOnline] = useState(true);
const [limitOnline] = useState(10); const [limitOnline] = useState(10);
const [offsetOnline, setOffsetOnline] = useState(0); const [offsetOnline, setOffsetOnline] = useState(0);
@ -45,6 +46,8 @@ export default function DetailRoomEducation() {
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [searchText, setSearchText] = useState(''); const [searchText, setSearchText] = useState('');
const dispatch = useDispatch(); const dispatch = useDispatch();
const isSGD = authentication?.user?.organization_name?.toLowerCase().includes('sở');
const getListOrganization = async () => { const getListOrganization = async () => {
try { try {
@ -358,7 +361,7 @@ export default function DetailRoomEducation() {
<div className="flex-1"> <div className="flex-1">
<Header <Header
icon={renderIconHome({ color: "#4D4D4D" })} icon={renderIconHome({ color: "#4D4D4D" })}
title={"Phòng giáo dục " + authentication.user.province} title={"Phòng giáo dục " + (isSGD ? `${authentication.user.province}` : `${authentication.user.district}`)}
manager={true} manager={true}
isBack={isBack} isBack={isBack}
/> />
@ -429,12 +432,12 @@ export default function DetailRoomEducation() {
}} }}
/> />
<PrimaryButton <PrimaryButton
isDisabled={false} isDisabled={searchText.length === 0}
onClick={handleSubmit} onClick={handleSubmit}
> >
{"Tìm kiếm"} {"Tìm kiếm"}
</PrimaryButton> </PrimaryButton>
<PrimaryButton onClick={handleExport}> <PrimaryButton isDisabled={listOrganization.length === 0} onClick={handleExport}>
Xuất excel Xuất excel
</PrimaryButton> </PrimaryButton>
</div> </div>
@ -443,22 +446,34 @@ export default function DetailRoomEducation() {
<RootSelect <RootSelect
data={LIST_SCHOOL_YEAR} data={LIST_SCHOOL_YEAR}
value={schoolYear} value={schoolYear}
setValue={setSchoolYear} setValue={(value) => {
setSchoolYear(value);
setIsFilterChanged(true);
}}
style={{flex: 1, minWidth: '200px', padding:'0 10px'}} style={{flex: 1, minWidth: '200px', padding:'0 10px'}}
/> />
<RootSelect <RootSelect
data={LIST_SEMESTER} data={LIST_SEMESTER}
value={semester} value={semester}
setValue={changeSemester} setValue={(value) => {
changeSemester(value);
setIsFilterChanged(true);
}}
style={{flex: 0.5, minWidth: '151px', padding:'0 10px'}} style={{flex: 0.5, minWidth: '151px', padding:'0 10px'}}
/> />
<RootSelect <RootSelect
data={getListMonthBySemester(semester.value)} data={getListMonthBySemester(semester.value)}
value={month} value={month}
setValue={setMonth} setValue={(value) => {
setMonth(value);
setIsFilterChanged(true);
}}
style={{flex: 0.5, minWidth: '150px', padding:'0 10px'}} style={{flex: 0.5, minWidth: '150px', padding:'0 10px'}}
/> />
<PrimaryButton onClick={handleFilter}> <PrimaryButton isDisabled={!isFilterChanged} onClick={() => {
handleFilter();
setIsFilterChanged(false);
}}>
Áp dụng Áp dụng
</PrimaryButton> </PrimaryButton>
</div> </div>

@ -34,6 +34,8 @@ export default function EducationDepartmentHome() {
const [isEndOnlineClasses, setIsEndOnlineClasses] = useState(false); const [isEndOnlineClasses, setIsEndOnlineClasses] = useState(false);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const dispatch = useDispatch(); const dispatch = useDispatch();
const isSGD = authentication?.user?.organization_name?.toLowerCase().includes('sở');
const getDataOrganization = async () => { const getDataOrganization = async () => {
try { try {
@ -200,7 +202,7 @@ export default function EducationDepartmentHome() {
<div className="flex-1"> <div className="flex-1">
<Header <Header
icon={renderIconHome({ color: "#4D4D4D" })} icon={renderIconHome({ color: "#4D4D4D" })}
title={"Sở giáo dục " + authentication.user.province} title={"Phòng giáo dục " + (isSGD ? `${authentication.user.province}` : `${authentication.user.district}`)}
manager={true} manager={true}
/> />
<div className="container-page-header container-page-sidebar"> <div className="container-page-header container-page-sidebar">
@ -254,7 +256,7 @@ export default function EducationDepartmentHome() {
<p className="education-department-home-note"> <p className="education-department-home-note">
Danh sách phòng giáo dục Danh sách phòng giáo dục
</p> </p>
<div className="d-flex detail-education-department-list-header"> <div className="detail-education-department-list-header">
<InputText <InputText
className="criteria-manage-search-input criteria-manage-item" className="criteria-manage-search-input criteria-manage-item"
value={searchText} value={searchText}
@ -269,12 +271,14 @@ export default function EducationDepartmentHome() {
} }
}} }}
/> />
<PrimaryButton <div style={{paddingTop: 10}}>
isDisabled={false} <PrimaryButton
onClick={handleSubmit} isDisabled={searchText.length === 0}
> onClick={handleSubmit}
{"Tìm kiếm"} >
</PrimaryButton> {"Tìm kiếm"}
</PrimaryButton>
</div>
</div> </div>
</div> </div>
<div onScroll={handleScroll} className="education-department-home-list-content scrollbar-custom"> <div onScroll={handleScroll} className="education-department-home-list-content scrollbar-custom">

@ -25,6 +25,8 @@ export default function OutstandingTeacher() {
const [firstTeacher, setFirstTeacher] = useState(); const [firstTeacher, setFirstTeacher] = useState();
const [listTeacher, setListTeacher] = useState([]); const [listTeacher, setListTeacher] = useState([]);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const isSGD = authentication?.user?.organization_name?.toLowerCase().includes('sở');
const getData = async () => { const getData = async () => {
setIsLoading(true) setIsLoading(true)
@ -72,8 +74,9 @@ export default function OutstandingTeacher() {
<div className="flex-1"> <div className="flex-1">
<Header <Header
icon={renderIconHome({ color: "#4D4D4D" })} icon={renderIconHome({ color: "#4D4D4D" })}
title={"Top 10 giáo viên tiêu biểu - " + authentication.user.province} title={"Top 10 giáo viên tiêu biểu - " + (isSGD ? `${authentication.user.province}` : `${authentication.user.district}`)}
isBack={true} isBack={true}
manager={true}
/> />
<div className="container-page-header container-page-sidebar"> <div className="container-page-header container-page-sidebar">
<div className="outstanding-teacher-container bg-outstanding-img"> <div className="outstanding-teacher-container bg-outstanding-img">
@ -102,14 +105,14 @@ export default function OutstandingTeacher() {
</PrimaryButton> </PrimaryButton>
</div> </div>
{!!firstTeacher && <div className="outstanding-teacher-best-container" > {!!firstTeacher && <div className="outstanding-teacher-best-container" >
<div className="outstanding-teacher-best-avatar-content" onClick={() => handleClickTeacherItem(firstTeacher)}> <div className="outstanding-teacher-best-avatar-content">
<div className="outstanding-teacher-best-avatar-box"> <div className="outstanding-teacher-best-avatar-box">
<img className="outstanding-teacher-best-crown" src="/assets/imgs/crown_warning.png" /> <img className="outstanding-teacher-best-crown" style={{cursor: 'default', zIndex: -1}} src="/assets/imgs/crown_warning.png" />
<img className="outstanding-teacher-best-avatar" src={configConstants.BASE_URL + firstTeacher?.avatar} /> <img className="outstanding-teacher-best-avatar" src={configConstants.BASE_URL + firstTeacher?.avatar} onClick={() => handleClickTeacherItem(firstTeacher)} />
</div> </div>
</div> </div>
<div className="outstanding-teacher-best-info"> <div className="outstanding-teacher-best-info">
<span className="outstanding-teacher-best-name">{firstTeacher?.teacher_name}</span> <span className="outstanding-teacher-best-name" onClick={() => handleClickTeacherItem(firstTeacher)}>{firstTeacher?.teacher_name}</span>
<div className="flex flex-m" style={{gap: '1.6rem', width: '100%', marginTop: '1rem'}}> <div className="flex flex-m" style={{gap: '1.6rem', width: '100%', marginTop: '1rem'}}>
<div className="flex-1 outstanding-teacher-best-address">{firstTeacher?.district_name}</div> <div className="flex-1 outstanding-teacher-best-address">{firstTeacher?.district_name}</div>
<div className="flex-1 outstanding-teacher-best-address">{firstTeacher?.school_name}</div> <div className="flex-1 outstanding-teacher-best-address">{firstTeacher?.school_name}</div>
@ -144,7 +147,7 @@ export default function OutstandingTeacher() {
<div className="outstanding-teacher-list"> <div className="outstanding-teacher-list">
{!isLoading && !listTeacher?.length && ( {!isLoading && !listTeacher?.length && (
<p style={{fontSize: '1.8rem', fontWeight: 700}}> <p style={{fontSize: '1.8rem', fontWeight: 700}}>
Không còn GV nào để hiển thị Không còn giáo viên nào để hiển thị
</p> </p>
)} )}
{listTeacher.map((item, index) => { {listTeacher.map((item, index) => {

@ -40,7 +40,6 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
max-height: 290px; max-height: 290px;
cursor: pointer;
.outstanding-teacher-best-avatar-box { .outstanding-teacher-best-avatar-box {
height: 90%; height: 90%;
@ -64,6 +63,7 @@
object-fit: cover; object-fit: cover;
border-radius: 50%; border-radius: 50%;
box-shadow: rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px; box-shadow: rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px;
cursor: pointer;
} }
} }
@ -80,6 +80,7 @@
font-size: 2.4rem; font-size: 2.4rem;
font-weight: 700; font-weight: 700;
align-self: center; align-self: center;
cursor: pointer;
} }
.outstanding-teacher-best-address { .outstanding-teacher-best-address {

Loading…
Cancel
Save