расписание и список разделены на разные компоненты

This commit is contained in:
goodmice 2022-06-02 14:40:06 +05:00
parent 294bc16a83
commit cdfbc2d25a
5 changed files with 177 additions and 171 deletions

View File

@ -0,0 +1,78 @@
import { memo, useCallback, useMemo, useState } from 'react'
import { Button, Modal } from 'antd'
import { EditableTable, makeActionHandler, makeTextColumn } from '@components/Table'
import { getPermissions } from '@utils/permissions'
import { DrillerService } from '@api'
const reqRule = [{ message: 'Обязательное поле!', required: true }]
const rowClassName = (record) => record.has ? 'driller_list_active' : ''
const columns = [
makeTextColumn('Фамилия', 'surname', undefined, undefined, undefined, { editable: true, formItemRules: reqRule }),
makeTextColumn('Имя', 'name', undefined, undefined, undefined, { editable: true, formItemRules: reqRule }),
makeTextColumn('Отчество', 'patronymic', undefined, undefined, undefined, { editable: true }),
]
export const DrillerList = memo(({ loading, drillers, onChange }) => {
const [showLoader, setShowLoader] = useState(false)
const [showModal, setShowModal] = useState(false)
const permissions = useMemo(() => getPermissions('Driller.edit', 'Driller.delete'), [])
const onModalOpen = useCallback(() => {
setShowModal(true)
}, [])
const onModalCancel = useCallback(() => {
setShowModal(false)
}, [])
const handlerProps = useMemo(() => ({
service: DrillerService,
setLoader: setShowLoader,
errorMsg: `Не удалось выполнить операцию`,
onComplete: onChange,
}), [onChange])
const actionHandlers = useMemo(() => ({
add: permissions.driller.edit && makeActionHandler('insert', handlerProps),
edit: permissions.driller.edit && makeActionHandler('update', handlerProps),
delete: permissions.driller.delete && makeActionHandler('delete', handlerProps),
}), [permissions, handlerProps])
return (
<>
<Modal
centered
width={500}
footer={null}
visible={showModal}
onCancel={onModalCancel}
title={'Список бурильщиков'}
>
<EditableTable
bordered
size={'small'}
pagination={false}
loading={loading || showLoader}
dataSource={drillers}
columns={columns}
scroll={{ y: '75vh', scrollToFirstRowOnChange: true }}
onRowAdd={actionHandlers.add}
onRowEdit={actionHandlers.edit}
onRowDelete={actionHandlers.delete}
rowClassName={rowClassName}
/>
</Modal>
<Button
onClick={onModalOpen}
loading={loading || showLoader}
style={{ marginRight: '10px' }}
>Список бурильщиков</Button>
</>
)
})
export default DrillerList

View File

@ -1,64 +1,29 @@
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import { Button, Modal, Typography } from 'antd'
import { Button, Modal } from 'antd'
import { useIdWell } from '@asb/context'
import {
makeTimeColumn,
makeGroupColumn,
makeDateColumn,
makeTextColumn,
EditableTable,
makeActionHandler,
makeSelectColumn,
} from '@components/Table'
import { invokeWebApiWrapperAsync } from '@components/factory'
import { DrillerService, ScheduleService } from '@api'
import { usePermissions } from '@utils/permissions'
import { getPermissions } from '@utils/permissions'
import { ScheduleService } from '@api'
const reqRule = [{ message: 'Обязательное поле!', required: true }]
const drillerColumns = [
makeTextColumn('Фамилия', 'surname', undefined, undefined, undefined, { editable: true, formItemRules: reqRule }),
makeTextColumn('Имя', 'name', undefined, undefined, undefined, { editable: true, formItemRules: reqRule }),
makeTextColumn('Отчество', 'patronymic', undefined, undefined, undefined, { editable: true }),
]
const scheduleColumns = [
makeGroupColumn('Рабочий период', [
makeDateColumn('Начало', 'drillStart', undefined, undefined, { editable: true, formItemRules: reqRule }),
makeDateColumn('Конец', 'drillEnd', undefined, undefined, { editable: true, formItemRules: reqRule }),
]),
makeGroupColumn('Смена', [
makeTimeColumn('Начало', 'shiftStart', undefined, undefined, { editable: true, formItemRules: reqRule }),
makeTimeColumn('Конец', 'shiftEnd', undefined, undefined, { editable: true, formItemRules: reqRule }),
]),
]
const drillerRowClassName = (record) => record.has ? 'driller_list_active' : ''
export const DrillerSchedule = memo(() => {
const [modalVisible, setModalVisible] = useState(false)
export const DrillerSchedule = memo(({ drillers, loading, onChange }) => {
const [modalVisible, setScheduleModalVisible] = useState(false)
const [showLoader, setShowLoader] = useState(false)
const [schedule, setSchedule] = useState([])
const [drillers, setDrillers] = useState([])
const [selectedDrillerId, setSelectedDrillerId] = useState(-1)
const idWell = useIdWell()
// const permissions = usePermissions(
// 'Driller.edit',
// 'Driller.delete',
// 'Schedule.edit',
// 'Schedule.delete'
// )
const permissions = {
driller: { edit: true, delete: true },
schedule: { edit: true, delete: true },
}
const drillerSchedule = useMemo(() =>
schedule.filter((v) => v.idDriller === selectedDrillerId)
, [schedule, selectedDrillerId])
const permissions = useMemo(() => getPermissions('Schedule.edit', 'Schedule.delete'), [])
const updateSchedule = useCallback(async () => invokeWebApiWrapperAsync(
async () => {
@ -67,48 +32,18 @@ export const DrillerSchedule = memo(() => {
}
), [idWell])
const updateList = useCallback(async () => invokeWebApiWrapperAsync(
async () => {
let drillers = await DrillerService.getAll()
drillers = drillers.map((val) => ({
...val,
has: schedule.findIndex((elm) => elm.idDriller === val.id) >= 0,
}))
drillers.sort((a, b) => +b.has - a.has)
setDrillers(drillers)
},
setShowLoader,
'Не удалось загрузить список бурильщиков',
'Получение списка бурильщиков'
), [schedule])
const onModalOpen = useCallback(() => {
setModalVisible(true)
setScheduleModalVisible(true)
}, [])
const onModalCancel = useCallback(() => {
setModalVisible(false)
}, [])
const onDrillerSelected = useCallback((selected) => {
setSelectedDrillerId(selected?.[0] ?? -1)
setScheduleModalVisible(false)
}, [])
useEffect(() => {
updateSchedule()
}, [updateSchedule])
useEffect(() => {
updateList()
}, [updateList])
const drillerHandlerProps = useMemo(() => ({
service: DrillerService,
setLoader: setShowLoader,
errorMsg: `Не удалось выполнить операцию`,
onComplete: updateSchedule,
}), [updateSchedule])
const scheduleHandlerProps = useMemo(() => ({
service: ScheduleService,
setLoader: setShowLoader,
@ -116,24 +51,39 @@ export const DrillerSchedule = memo(() => {
onComplete: updateSchedule,
}), [updateSchedule])
const newScheduleParser = useCallback((record) => ({
...record,
idWell,
idDriller: selectedDrillerId
}), [idWell, selectedDrillerId])
const newScheduleParser = useCallback((record) => ({ ...record, idWell }), [idWell])
const actionHandlers = useMemo(() => ({
driller: {
add: permissions.driller.edit && makeActionHandler('insert', drillerHandlerProps),
edit: permissions.driller.edit && makeActionHandler('update', drillerHandlerProps),
delete: permissions.driller.delete && makeActionHandler('delete', drillerHandlerProps),
},
schedule: {
add: permissions.schedule.edit && makeActionHandler('insert', scheduleHandlerProps, newScheduleParser),
edit: permissions.schedule.edit && makeActionHandler('update', scheduleHandlerProps),
delete: permissions.schedule.delete && makeActionHandler('delete', scheduleHandlerProps),
},
}), [permissions, drillerHandlerProps, scheduleHandlerProps, newScheduleParser])
add: permissions.schedule.edit && makeActionHandler('insert', scheduleHandlerProps, newScheduleParser),
edit: permissions.schedule.edit && makeActionHandler('update', scheduleHandlerProps),
delete: permissions.schedule.delete && makeActionHandler('delete', scheduleHandlerProps),
}), [permissions, scheduleHandlerProps, newScheduleParser])
const scheduleColumns = useMemo(() => {
const options = drillers.map(({ id, name, surname, patronymic }) => ({
value: id,
label: `${surname} ${name} ${patronymic}`,
}))
return [
makeSelectColumn('Бурильщик', 'idDriller', options, undefined, {
editable: true,
formItemRules: reqRule,
}, {
showSearch: true,
filterOption: (input, option) =>
String(option?.label ?? '').toLowerCase().indexOf(input.toLowerCase()) >= 0
}),
makeGroupColumn('Рабочий период', [
makeDateColumn('Начало', 'drillStart', undefined, undefined, { editable: true, formItemRules: reqRule }),
makeDateColumn('Конец', 'drillEnd', undefined, undefined, { editable: true, formItemRules: reqRule }),
]),
makeGroupColumn('Смена', [
makeTimeColumn('Начало', 'shiftStart', undefined, undefined, { editable: true, formItemRules: reqRule }),
makeTimeColumn('Конец', 'shiftEnd', undefined, undefined, { editable: true, formItemRules: reqRule }),
]),
]
}, [drillers])
return (
<>
@ -145,44 +95,25 @@ export const DrillerSchedule = memo(() => {
onCancel={onModalCancel}
title={'Настройка бурильщиков и расписаний'}
>
<div className={'drill_schedule'}>
<div className={'driller_list list'}>
<Typography.Title level={4}>Список бурильщиков</Typography.Title>
<EditableTable
bordered
size={'small'}
pagination={false}
loading={showLoader}
dataSource={drillers}
columns={drillerColumns}
scroll={{ y: '75vh', scrollToFirstRowOnChange: true }}
onRowAdd={actionHandlers.driller.add}
onRowEdit={actionHandlers.driller.edit}
onRowDelete={actionHandlers.driller.delete}
rowClassName={drillerRowClassName}
rowSelection={{ type: 'radio', onChange: onDrillerSelected }}
rowKey={'id'}
/>
</div>
<div className={'schedule_list list'}>
<Typography.Title level={4}>Смены бурильщика</Typography.Title>
<EditableTable
sticky
bordered
size={'small'}
pagination={false}
loading={showLoader}
columns={scheduleColumns}
dataSource={drillerSchedule}
scroll={{ y: '75vh', scrollToFirstRowOnChange: true }}
onRowAdd={selectedDrillerId >= 0 && actionHandlers.schedule.add}
onRowEdit={actionHandlers.schedule.edit}
onRowDelete={actionHandlers.schedule.delete}
/>
</div>
</div>
<EditableTable
sticky
bordered
size={'small'}
pagination={false}
loading={loading || showLoader}
dataSource={schedule}
columns={scheduleColumns}
scroll={{ y: '75vh', scrollToFirstRowOnChange: true }}
onRowAdd={actionHandlers.add}
onRowEdit={actionHandlers.edit}
onRowDelete={actionHandlers.delete}
/>
</Modal>
<Button onClick={onModalOpen} loading={showLoader}>Расписание бурильщиков</Button>
<Button
onClick={onModalOpen}
loading={loading || showLoader}
style={{ marginRight: '10px' }}
>Расписание бурильщиков</Button>
</>
)
})

View File

@ -1,4 +1,4 @@
import { memo, useCallback, useEffect, useState } from 'react'
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import { InputNumber } from 'antd'
import moment from 'moment'
@ -6,9 +6,11 @@ import { useIdWell } from '@asb/context'
import LoaderPortal from '@components/LoaderPortal'
import { DateRangeWrapper } from '@components/Table'
import { invokeWebApiWrapperAsync } from '@components/factory'
import { DetectedOperationService, TelemetryDataSaubService } from '@api'
import { range } from '@utils'
import { DetectedOperationService, DrillerService, TelemetryDataSaubService } from '@api'
import { getPermissions } from '@utils/permissions'
import { arrayOrDefault, range } from '@utils'
import DrillerList from './DrillerList'
import DrillerSchedule from './DrillerSchedule'
import OperationsChart from './OperationsChart'
import OperationsTable from './OperationsTable'
@ -21,9 +23,13 @@ export const Operations = memo(() => {
const [yDomain, setYDomain] = useState(20)
const [dates, setDates] = useState()
const [data, setData] = useState([])
const [drillers, setDrillers] = useState([])
const [drillersLoader, setDrillersLoader] = useState(false)
const idWell = useIdWell()
const permissions = useMemo(() => getPermissions('Driller.get'), [])
const disabledDates = useCallback((current) => current && !moment(current).isBetween(...dateRange, 'day', '[]'), [dateRange])
const disabledTimes = useCallback((date) => ({
@ -32,6 +38,21 @@ export const Operations = memo(() => {
disabledSeconds: () => range(60).filter(s => date && !moment(date).seconds(s).isBetween(...dateRange, 'second', '[]'))
}), [dateRange])
const updateDrillers = useCallback(async () => invokeWebApiWrapperAsync(
async () => {
const drillers = arrayOrDefault(await DrillerService.getAll())
setDrillers(drillers)
},
setDrillersLoader,
'Не удалось загрузить список бурильщиков',
'Получение списка бурильщиков'
), [])
useEffect(() => {
if (permissions.driller.get)
updateDrillers()
}, [updateDrillers, permissions])
useEffect(() => invokeWebApiWrapperAsync(
async () => {
const dates = await TelemetryDataSaubService.getDataDatesRange(idWell)
@ -78,7 +99,12 @@ export const Operations = memo(() => {
addonBefore={'Верхняя граница'}
style={{ marginRight: '10px' }}
/>
<DrillerSchedule />
{permissions.driller.get && (
<>
<DrillerSchedule drillers={drillers} loading={drillersLoader} onChange={updateDrillers} />
<DrillerList drillers={drillers} loading={drillersLoader} onChange={updateDrillers} />
</>
)}
</div>
<LoaderPortal show={isLoading}>
<div className={'page-main'}>

View File

@ -8,6 +8,7 @@
.drill_schedule {
display: flex;
flex-direction: column;
width: 100%;
height: 75vh;
align-items: stretch;
@ -21,29 +22,5 @@
& > .ant-list, .ant-table {
flex: 1;
}
& > .buttons {
display: flex;
& > * {
flex: 1;
}
}
}
& > .driller_list {
flex: 2;
width: 10vw;
margin-right: 15px;
.driller_list_active {
background-color: rgba(0, 255, 0, .25);
}
}
& > .schedule_list {
width: 10vw;
flex: 3;
margin-left: 15px;
}
}

View File

@ -1,6 +1,4 @@
import { useMemo } from 'react'
import { getUserPermissions, getUserRoles } from './storage'
import { getUserLogin, getUserPermissions, getUserRoles } from './storage'
export type Role = string
export type Permission = string
@ -13,19 +11,15 @@ export function isRequestType(value: string): value is ServiceRequestType {
return ['get', 'edit', 'delete'].includes(value)
}
export const usePermissions = (...values: PermissionRequest[]) => {
const result = useMemo(() => {
const permissions: Record<string, Partial<Record<ServiceRequestType, boolean>>> = {}
values.forEach((key) => {
const [service, type] = key.toLowerCase().split('.')
if (!isRequestType(type)) return
permissions[service] = permissions[service] ?? {}
permissions[service][type] = hasPermission(key)
})
return permissions
}, [values])
return result
export const getPermissions = (...values: PermissionRequest[]) => {
const permissions: Record<string, Partial<Record<ServiceRequestType, boolean>>> = {}
values.forEach((key) => {
const [service, type] = key.toLowerCase().split('.')
if (!isRequestType(type)) return
permissions[service] = permissions[service] ?? {}
permissions[service][type] = getUserLogin() === 'dev' || hasPermission(key)
})
return permissions
}
export const hasPermission = (permission?: Permission | Permission[], userPermissions?: Permission[]): boolean => {