Update view detail Working review

This commit is contained in:
nguentrungthat 2025-02-17 16:14:52 +07:00
parent 5cfd78d2c0
commit f5e4d7b405
4 changed files with 205 additions and 115 deletions

View File

@ -289,33 +289,32 @@ class TrackingController extends Controller
$lateMorning = 0; $lateMorning = 0;
$onTimeAfternoon = 0; $onTimeAfternoon = 0;
$lateAfternoon = 0; $lateAfternoon = 0;
$valueTracking = $trackingData->get(); $returnTracking = $trackingData->get();
$listLate = [];
$trackingData->get()->groupBy(function ($record) { $returnTracking->groupBy(function ($record) {
return Carbon::parse($record->time_string)->toDateString(); return Carbon::parse($record->time_string)->toDateString();
})->each(function ($records, $date) use ($trackingData, &$onTimeMorning, &$lateMorning, &$onTimeAfternoon, &$lateAfternoon, &$datesChecked) { })->each(function ($records, $date) use ($userID, &$listLate, &$onTimeMorning, &$lateMorning, &$onTimeAfternoon, &$lateAfternoon, &$datesChecked) {
$morningCheck = $records->filter(function ($record) { $morningCheck = $records->filter(function ($record) {
return Carbon::parse($record->time_string)->hour < 12; return Carbon::parse($record->time_string)->hour < 12;
})->sortBy('time_string')->first(); })->sortBy('time_string')->first();
$afternoonCheck = $records->filter(function ($record) { $afternoonCheck = $records->filter(function ($record) {
return Carbon::parse($record->time_string)->hour >= 12; $time = Carbon::parse($record->time_string)->hour;
return $time >= 12 && $time <= 14;
})->sortBy('time_string')->first(); })->sortBy('time_string')->first();
$morningTime = Carbon::parse($date)->setTime(7, 40, 0); $morningTime = Carbon::parse($date)->setTime(7, 40, 0);
$afternoonTime = Carbon::parse($date)->setTime(13, 10, 0); $afternoonTime = Carbon::parse($date)->setTime(13, 10, 0);
$checkOutAfternoonTime = Carbon::parse($date)->setTime(15, 00, 0); $checkOutAfternoonTime = Carbon::parse($date)->setTime(15, 00, 0);
$checkOutAfternoon = $trackingData->where(
DB::raw("STR_TO_DATE(time_string, '%Y-%m-%d %H:%i:%s')"),
'<=',
$date . ' 23:59:59'
)->where("status", "check out")->first();
if ($morningCheck) { if ($morningCheck) {
$checkInTime = Carbon::parse($morningCheck->time_string); $checkInTime = Carbon::parse($morningCheck->time_string);
if ($checkInTime->lessThanOrEqualTo($morningTime)) { if ($checkInTime->lessThanOrEqualTo($morningTime)) {
$onTimeMorning++; $onTimeMorning++;
} else { } else {
array_push($listLate, $morningCheck->id);
$lateMorning++; $lateMorning++;
} }
} }
@ -325,22 +324,40 @@ class TrackingController extends Controller
if ($checkInTime->lessThanOrEqualTo($afternoonTime)) { if ($checkInTime->lessThanOrEqualTo($afternoonTime)) {
$onTimeAfternoon++; $onTimeAfternoon++;
} else { } else {
array_push($listLate, $afternoonCheck->id);
$lateAfternoon++; $lateAfternoon++;
} }
} else { } else {
// print ($date . "\n");
$checkOutAfternoon = Tracking::where('user_id', $userID)->whereBetween(
DB::raw("STR_TO_DATE(time_string, '%Y-%m-%d %H:%i:%s')"),
[$date, $date . ' 23:59:59'],
)->where("status", "check out")->first();
// check if not check-in afternoon but has check out // check if not check-in afternoon but has check out
if ($checkOutAfternoon && $checkOutAfternoonTime->lessThanOrEqualTo(Carbon::parse($checkOutAfternoon->time_string))) { if ($checkOutAfternoon) {
$onTimeAfternoon++; $timeCheck = Carbon::parse($checkOutAfternoon->time_string);
// print ($timeCheck . "\n");
if ($checkOutAfternoon && $timeCheck->greaterThanOrEqualTo($checkOutAfternoonTime)) {
$onTimeAfternoon++;
}
} }
} }
}); });
// ** Add `isLate` flag to each record **
foreach ($returnTracking as $record) {
if (in_array($record->id, $listLate)) {
$record->isLate = true;
}
}
return AbstractController::ResultSuccess([ return AbstractController::ResultSuccess([
'on_time_morning' => $onTimeMorning, 'on_time_morning' => $onTimeMorning,
'late_morning' => $lateMorning, 'late_morning' => $lateMorning,
'on_time_afternoon' => $onTimeAfternoon, 'on_time_afternoon' => $onTimeAfternoon,
'late_afternoon' => $lateAfternoon, 'late_afternoon' => $lateAfternoon,
'value' => $valueTracking 'value' => $returnTracking
]); ]);
} }
} }

View File

@ -11,6 +11,7 @@ import {
MultiSelect, MultiSelect,
Pagination, Pagination,
RadioGroup, RadioGroup,
ScrollArea,
Select, Select,
Skeleton, Skeleton,
Table, Table,
@ -85,6 +86,8 @@ export const DataTableAll = ({
size, size,
infoTotal, infoTotal,
componentRight, componentRight,
height = 600,
keyHighlight = '',
}: { }: {
data: any[] data: any[]
columns: Column[] columns: Column[]
@ -94,6 +97,8 @@ export const DataTableAll = ({
size: string size: string
infoTotal?: React.ReactNode // Set the type to ReactNode to allow JSX elements infoTotal?: React.ReactNode // Set the type to ReactNode to allow JSX elements
componentRight?: React.ReactNode componentRight?: React.ReactNode
height?: number
keyHighlight?: string
}) => { }) => {
const [Tdata, setTData] = useState<any[]>(data) const [Tdata, setTData] = useState<any[]>(data)
// const [tempData, setTempData] = useState<any[]>([]) // const [tempData, setTempData] = useState<any[]>([])
@ -206,6 +211,9 @@ export const DataTableAll = ({
? 'var(--mantine-color-blue-light)' ? 'var(--mantine-color-blue-light)'
: undefined : undefined
} }
style={{
backgroundColor: element[keyHighlight] ? '#ff70704d' : 'transparent',
}}
> >
<Table.Td display={checkBox ? 'block' : 'none'}> <Table.Td display={checkBox ? 'block' : 'none'}>
<Checkbox <Checkbox
@ -369,43 +377,45 @@ export const DataTableAll = ({
</Box> </Box>
{componentRight} {componentRight}
</Box> </Box>
<Box className={classes.box}> <Box className={classes.box} style={{ height: height + 50 }}>
<Table <ScrollArea h={height}>
stickyHeader <Table
stickyHeaderOffset={-1} stickyHeader
striped stickyHeaderOffset={-1}
highlightOnHover striped
withTableBorder highlightOnHover
withColumnBorders withTableBorder
> withColumnBorders
<Table.Thead className={classes.headers}> >
<Table.Tr> <Table.Thead className={classes.headers}>
<Table.Th display={checkBox ? 'block' : 'none'}> <Table.Tr>
<Checkbox <Table.Th display={checkBox ? 'block' : 'none'}>
aria-label="Select row" <Checkbox
checked={ aria-label="Select row"
checkSubArray(Tdata, selectedRows) && checked={
Tdata.length === selectedRows.length checkSubArray(Tdata, selectedRows) &&
} Tdata.length === selectedRows.length
onChange={(event) => }
setSelectedRows( onChange={(event) =>
event.currentTarget.checked setSelectedRows(
? (pre) => [...pre, ...Tdata] event.currentTarget.checked
: selectedRows.filter( ? (pre) => [...pre, ...Tdata]
(item) => : selectedRows.filter(
!Tdata.some((removeItem) => (item) =>
areObjectsEqual(item, removeItem), !Tdata.some((removeItem) =>
), areObjectsEqual(item, removeItem),
), ),
) ),
} )
/> }
</Table.Th> />
{headers} </Table.Th>
</Table.Tr> {headers}
</Table.Thead> </Table.Tr>
<Table.Tbody>{rows}</Table.Tbody> </Table.Thead>
</Table> <Table.Tbody>{rows}</Table.Tbody>
</Table>
</ScrollArea>
</Box> </Box>
</Container> </Container>
) )

View File

@ -702,6 +702,35 @@ const StaffEvaluation = () => {
}, },
] ]
const columnsDetailWorking = [
{
name: 'name',
size: '25%',
header: 'Name',
},
{
name: 'time_string',
size: '25%',
header: 'Time',
render: (row: any) => {
return moment(row.time_string).format('YYYY/MM/DD - HH:mm:ss')
},
},
{
name: 'status',
size: '25%',
header: 'Status',
},
{
name: 'created_at',
size: '25%',
header: 'Created at',
render: (row: any) => {
return moment(row.created_at).format('YYYY/MM/DD - HH:mm:ss')
},
},
]
const handleCreate = async (values: DataProjectReview) => { const handleCreate = async (values: DataProjectReview) => {
try { try {
const res = await post(projectReviewAdd, { const res = await post(projectReviewAdd, {
@ -1054,71 +1083,104 @@ const StaffEvaluation = () => {
</Box> </Box>
) : ( ) : (
<Box> <Box>
<Box className={classes.chartContainer} display="flex"> <Tabs defaultValue="overview" orientation="vertical">
<PieChart <Tabs.List justify="center">
withLabelsLine <Tabs.Tab value="overview">Overview</Tabs.Tab>
labelsPosition="outside" <Tabs.Tab value="detail">Detail</Tabs.Tab>
labelsType="value" </Tabs.List>
withLabels={dataSummaryTracking.value.length > 0}
withTooltip <Tabs.Panel value="overview">
data={ <Box style={{ height: 350, marginTop: 8 }}>
dataSummaryTracking.value.length > 0 <Box className={classes.chartContainer} display="flex">
? [ <PieChart
{ withLabelsLine
name: 'On time morning', labelsPosition="outside"
value: dataSummaryTracking?.on_time_morning ?? 0, labelsType="value"
color: 'lime', withLabels={dataSummaryTracking.value.length > 0}
}, withTooltip
{ data={
name: 'Late morning', dataSummaryTracking.value.length > 0
value: dataSummaryTracking?.late_morning ?? 0, ? [
color: 'red', {
}, name: 'On time morning',
{ value:
name: 'On time afternoon', dataSummaryTracking?.on_time_morning ?? 0,
value: dataSummaryTracking?.on_time_afternoon ?? 0, color: 'lime',
color: 'teal', },
}, {
{ name: 'Late morning',
name: 'Late afternoon', value: dataSummaryTracking?.late_morning ?? 0,
value: dataSummaryTracking?.late_afternoon ?? 0, color: 'red',
color: 'orange', },
}, {
] name: 'On time afternoon',
: [ value:
{ dataSummaryTracking?.on_time_afternoon ?? 0,
name: 'No data', color: 'teal',
value: 1, },
color: 'gray.6', {
}, name: 'Late afternoon',
] value:
} dataSummaryTracking?.late_afternoon ?? 0,
/> color: 'orange',
</Box> },
<Box className={classes.boxContainer} display="flex"> ]
<Box className={classes.boxContainer} display="flex"> : [
<div className={classes.boxColorLime}></div> {
<div style={{ paddingLeft: '10px', paddingRight: '20px' }}> name: 'No data',
On time morning value: 1,
</div> color: 'gray.6',
</Box> },
<Box className={classes.boxContainer} display="flex"> ]
<div className={classes.boxColorRed}></div> }
<div style={{ paddingLeft: '10px', paddingRight: '20px' }}> />
Late morning </Box>
</div> <Box className={classes.boxContainer} display="flex">
</Box> <Box className={classes.boxContainer} display="flex">
<Box className={classes.boxContainer} display="flex"> <div className={classes.boxColorLime}></div>
<div className={classes.boxColorTeal}></div> <div
<div style={{ paddingLeft: '10px', paddingRight: '20px' }}> style={{ paddingLeft: '10px', paddingRight: '20px' }}
On time afternoon >
</div> On time morning
</Box> </div>
<Box className={classes.boxContainer} display="flex"> </Box>
<div className={classes.boxColorOrange}></div> <Box className={classes.boxContainer} display="flex">
<div style={{ paddingLeft: '10px' }}>Late afternoon</div> <div className={classes.boxColorRed}></div>
</Box> <div
</Box> style={{ paddingLeft: '10px', paddingRight: '20px' }}
>
Late morning
</div>
</Box>
<Box className={classes.boxContainer} display="flex">
<div className={classes.boxColorTeal}></div>
<div
style={{ paddingLeft: '10px', paddingRight: '20px' }}
>
On time afternoon
</div>
</Box>
<Box className={classes.boxContainer} display="flex">
<div className={classes.boxColorOrange}></div>
<div style={{ paddingLeft: '10px' }}>
Late afternoon
</div>
</Box>
</Box>
</Box>
</Tabs.Panel>
<Tabs.Panel value="detail">
<Box style={{ marginTop: 8 }}>
<DataTableAll
data={dataSummaryTracking.value}
columns={columnsDetailWorking}
size=""
height={300}
keyHighlight={'isLate'}
/>
</Box>
</Tabs.Panel>
</Tabs>
</Box> </Box>
)} )}
<Box className={classes.pjParticipatingContainer}> <Box className={classes.pjParticipatingContainer}>
@ -1150,6 +1212,7 @@ const StaffEvaluation = () => {
data={dataPJParticipating} data={dataPJParticipating}
columns={columnsPJParticipating} columns={columnsPJParticipating}
size="" size=""
height={300}
/> />
)} )}
</Box> </Box>

View File

@ -14,7 +14,7 @@ import {
Modal, Modal,
MultiSelect, MultiSelect,
Text, Text,
TextInput TextInput,
} from '@mantine/core' } from '@mantine/core'
import { useForm } from '@mantine/form' import { useForm } from '@mantine/form'
import { IconEdit, IconX } from '@tabler/icons-react' import { IconEdit, IconX } from '@tabler/icons-react'