Добавлены фильтры на страницу админки

This commit is contained in:
Александр Сироткин 2022-03-18 17:37:05 +05:00
parent ba88454500
commit d98e223468
12 changed files with 269 additions and 124 deletions

View File

@ -1,4 +1,5 @@
import { memo, useCallback, useEffect, useState } from 'react' import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import { Input } from 'antd'
import { import {
EditableTable, EditableTable,
@ -9,7 +10,6 @@ import {
defaultPagination, defaultPagination,
makeTimezoneColumn makeTimezoneColumn
} from '@components/Table' } from '@components/Table'
import LoaderPortal from '@components/LoaderPortal'
import { invokeWebApiWrapperAsync } from '@components/factory' import { invokeWebApiWrapperAsync } from '@components/factory'
import { AdminClusterService, AdminDepositService } from '@api' import { AdminClusterService, AdminDepositService } from '@api'
import { arrayOrDefault } from '@utils' import { arrayOrDefault } from '@utils'
@ -21,9 +21,11 @@ import { coordsFixed } from './DepositController'
export const ClusterController = memo(() => { export const ClusterController = memo(() => {
const [deposits, setDeposits] = useState([]) const [deposits, setDeposits] = useState([])
const [clusters, setClusters] = useState([]) const [clusters, setClusters] = useState([])
const [filteredClusters, setFilteredClusters] = useState([])
const [showLoader, setShowLoader] = useState(false) const [showLoader, setShowLoader] = useState(false)
const [searchValue, setSearchValue] = useState('')
const clusterColumns = [ const clusterColumns = useMemo(() => [
makeSelectColumn('Месторождение', 'idDeposit', deposits, '--', { makeSelectColumn('Месторождение', 'idDeposit', deposits, '--', {
width: 200, width: 200,
editable: true, editable: true,
@ -38,7 +40,7 @@ export const ClusterController = memo(() => {
makeColumn('Широта', 'latitude', { width: 150, editable: true, render: coordsFixed }), makeColumn('Широта', 'latitude', { width: 150, editable: true, render: coordsFixed }),
makeColumn('Долгота', 'longitude', { width: 150, editable: true, render: coordsFixed }), makeColumn('Долгота', 'longitude', { width: 150, editable: true, render: coordsFixed }),
makeTimezoneColumn('Зона', 'timezone', null, true, { width: 150 }), makeTimezoneColumn('Зона', 'timezone', null, true, { width: 150 }),
] ], [deposits])
const updateTable = useCallback(() => invokeWebApiWrapperAsync( const updateTable = useCallback(() => invokeWebApiWrapperAsync(
async () => { async () => {
@ -63,27 +65,43 @@ export const ClusterController = memo(() => {
useEffect(updateTable, [updateTable]) useEffect(updateTable, [updateTable])
const handlerProps = { useEffect(() => {
setFilteredClusters(clusters.filter((cluster) => cluster && (!searchValue || [
cluster.caption ?? '',
cluster.latitude?.toString ?? '',
cluster.longitude?.toString() ?? '',
].join(' ').toLowerCase().includes(searchValue.toLowerCase()))))
}, [clusters, searchValue])
const handlerProps = useMemo(() => ({
service: AdminClusterService, service: AdminClusterService,
setLoader: setShowLoader, setLoader: setShowLoader,
errorMsg: `Не удалось выполнить операцию`, errorMsg: `Не удалось выполнить операцию`,
onComplete: updateTable, onComplete: updateTable,
} }), [updateTable])
return ( return (
<LoaderPortal show={showLoader}> <>
<Input.Search
style={{ margin: '15px 0' }}
placeholder={'Введите текст для поиска...'}
onChange={(e) => setSearchValue(e.target.value)}
value={searchValue}
loading={showLoader}
/>
<EditableTable <EditableTable
size={'small'}
bordered bordered
dataSource={clusters} size={'small'}
loading={showLoader}
columns={clusterColumns} columns={clusterColumns}
dataSource={filteredClusters}
pagination={defaultPagination} pagination={defaultPagination}
onRowAdd={hasPermission('AdminCluster.edit') && makeActionHandler('insert', handlerProps, null, 'Добавление куста')} onRowAdd={hasPermission('AdminCluster.edit') && makeActionHandler('insert', handlerProps, null, 'Добавление куста')}
onRowEdit={hasPermission('AdminCluster.edit') && makeActionHandler('update', handlerProps, null, 'Редактирование куста')} onRowEdit={hasPermission('AdminCluster.edit') && makeActionHandler('update', handlerProps, null, 'Редактирование куста')}
onRowDelete={hasPermission('AdminCluster.delete') && makeActionHandler('delete', handlerProps, null, 'Удаление куста')} onRowDelete={hasPermission('AdminCluster.delete') && makeActionHandler('delete', handlerProps, null, 'Удаление куста')}
tableName={'admin_cluster_controller'} tableName={'admin_cluster_controller'}
/> />
</LoaderPortal> </>
) )
}) })

View File

@ -1,4 +1,5 @@
import { memo, useCallback, useEffect, useState } from 'react' import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import { Input } from 'antd'
import { import {
EditableTable, EditableTable,
@ -8,7 +9,6 @@ import {
makeSelectColumn, makeSelectColumn,
defaultPagination defaultPagination
} from '@components/Table' } from '@components/Table'
import LoaderPortal from '@components/LoaderPortal'
import { invokeWebApiWrapperAsync } from '@components/factory' import { invokeWebApiWrapperAsync } from '@components/factory'
import { AdminCompanyService, AdminCompanyTypeService } from '@api' import { AdminCompanyService, AdminCompanyTypeService } from '@api'
import { arrayOrDefault } from '@utils' import { arrayOrDefault } from '@utils'
@ -19,7 +19,9 @@ import { hasPermission } from '@utils/permissions'
export const CompanyController = memo(() => { export const CompanyController = memo(() => {
const [columns, setColumns] = useState([]) const [columns, setColumns] = useState([])
const [companies, setCompanies] = useState([]) const [companies, setCompanies] = useState([])
const [filteredCompanies, setFilteredCompanies] = useState([])
const [showLoader, setShowLoader] = useState(false) const [showLoader, setShowLoader] = useState(false)
const [searchValue, setSearchValue] = useState('')
const updateTable = useCallback(async () => { const updateTable = useCallback(async () => {
const companies = await AdminCompanyService.getAll() const companies = await AdminCompanyService.getAll()
@ -53,7 +55,13 @@ export const CompanyController = memo(() => {
'Получение списка типов команд' 'Получение списка типов команд'
), [updateTable]) ), [updateTable])
const handlerProps = { useEffect(() => {
setFilteredCompanies(companies.filter((company) => company && (!searchValue ||
company.caption?.toLowerCase()?.includes(searchValue.toLowerCase())
)))
}, [companies, searchValue])
const handlerProps = useMemo(() => ({
service: AdminCompanyService, service: AdminCompanyService,
setLoader: setShowLoader, setLoader: setShowLoader,
errorMsg: `Не удалось выполнить операцию`, errorMsg: `Не удалось выполнить операцию`,
@ -63,22 +71,30 @@ export const CompanyController = memo(() => {
`Не удалось обновить список компаний`, `Не удалось обновить список компаний`,
'Получение списка компаний' 'Получение списка компаний'
), ),
} }), [updateTable])
return ( return (
<LoaderPortal show={showLoader}> <>
<Input.Search
style={{ margin: '15px 0' }}
placeholder={'Введите текст для поиска...'}
onChange={(e) => setSearchValue(e.target.value)}
value={searchValue}
loading={showLoader}
/>
<EditableTable <EditableTable
size={'small'}
bordered bordered
size={'small'}
columns={columns} columns={columns}
dataSource={companies} loading={showLoader}
dataSource={filteredCompanies}
pagination={defaultPagination} pagination={defaultPagination}
onRowAdd={hasPermission('AdminCompany.edit') && makeActionHandler('insert', handlerProps, null, 'Добавлениее компаний')} onRowAdd={hasPermission('AdminCompany.edit') && makeActionHandler('insert', handlerProps, null, 'Добавлениее компаний')}
onRowEdit={hasPermission('AdminCompany.edit') && makeActionHandler('update', handlerProps, null, 'Редактирование команий')} onRowEdit={hasPermission('AdminCompany.edit') && makeActionHandler('update', handlerProps, null, 'Редактирование команий')}
onRowDelete={hasPermission('AdminCompany.delete') && makeActionHandler('delete', handlerProps, null, 'Удаление компаний')} onRowDelete={hasPermission('AdminCompany.delete') && makeActionHandler('delete', handlerProps, null, 'Удаление компаний')}
tableName={'admin_company_controller'} tableName={'admin_company_controller'}
/> />
</LoaderPortal> </>
) )
}) })

View File

@ -1,4 +1,5 @@
import { memo, useCallback, useEffect, useState } from 'react' import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import { Input } from 'antd'
import { import {
EditableTable, EditableTable,
@ -7,7 +8,6 @@ import {
makeStringSorter, makeStringSorter,
defaultPagination defaultPagination
} from '@components/Table' } from '@components/Table'
import LoaderPortal from '@components/LoaderPortal'
import { invokeWebApiWrapperAsync } from '@components/factory' import { invokeWebApiWrapperAsync } from '@components/factory'
import { AdminCompanyTypeService } from '@api' import { AdminCompanyTypeService } from '@api'
import { arrayOrDefault } from '@utils' import { arrayOrDefault } from '@utils'
@ -25,7 +25,9 @@ const columns = [
export const CompanyTypeController = memo(() => { export const CompanyTypeController = memo(() => {
const [companyTypes, setCompanyTypes] = useState([]) const [companyTypes, setCompanyTypes] = useState([])
const [filteredCompanyTypes, setFilteredCompanyTypes] = useState([])
const [showLoader, setShowLoader] = useState(false) const [showLoader, setShowLoader] = useState(false)
const [searchValue, setSearchValue] = useState('')
const updateTable = useCallback(() => invokeWebApiWrapperAsync( const updateTable = useCallback(() => invokeWebApiWrapperAsync(
async() => { async() => {
@ -39,27 +41,41 @@ export const CompanyTypeController = memo(() => {
useEffect(updateTable, [updateTable]) useEffect(updateTable, [updateTable])
const handlerProps = { useEffect(() => {
setFilteredCompanyTypes(companyTypes.filter((companyType) => companyType && (!searchValue ||
companyType.caption?.toLowerCase()?.includes(searchValue.toLowerCase())
)))
}, [companyTypes, searchValue])
const handlerProps = useMemo(() => ({
service: AdminCompanyTypeService, service: AdminCompanyTypeService,
setLoader: setShowLoader, setLoader: setShowLoader,
errorMsg: `Не удалось выполнить операцию`, errorMsg: `Не удалось выполнить операцию`,
onComplete: updateTable, onComplete: updateTable,
} }), [updateTable])
return ( return (
<LoaderPortal show={showLoader}> <>
<Input.Search
style={{ margin: '15px 0' }}
placeholder={'Введите текст для поиска...'}
onChange={(e) => setSearchValue(e.target.value)}
value={searchValue}
loading={showLoader}
/>
<EditableTable <EditableTable
bordered bordered
size={'small'} size={'small'}
columns={columns} columns={columns}
dataSource={companyTypes} loading={showLoader}
pagination={defaultPagination} pagination={defaultPagination}
dataSource={filteredCompanyTypes}
onRowAdd={hasPermission('AdminCompanyType.edit') && makeActionHandler('insert', handlerProps, null, 'Добавление типа компаний')} onRowAdd={hasPermission('AdminCompanyType.edit') && makeActionHandler('insert', handlerProps, null, 'Добавление типа компаний')}
onRowEdit={hasPermission('AdminCompanyType.edit') && makeActionHandler('update', handlerProps, null, 'Редактирование типа компаний')} onRowEdit={hasPermission('AdminCompanyType.edit') && makeActionHandler('update', handlerProps, null, 'Редактирование типа компаний')}
onRowDelete={hasPermission('AdminCompanyType.delete') && makeActionHandler('delete', handlerProps, null, 'Удаление типа компаний')} onRowDelete={hasPermission('AdminCompanyType.delete') && makeActionHandler('delete', handlerProps, null, 'Удаление типа компаний')}
tableName={'admin_company_type_controller'} tableName={'admin_company_type_controller'}
/> />
</LoaderPortal> </>
) )
}) })

View File

@ -1,12 +1,12 @@
import { memo, useCallback, useEffect, useState } from 'react' import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import { Input } from 'antd'
import LoaderPortal from '@components/LoaderPortal'
import { invokeWebApiWrapperAsync } from '@components/factory' import { invokeWebApiWrapperAsync } from '@components/factory'
import { EditableTable, makeColumn, makeActionHandler, defaultPagination, makeTimezoneColumn } from '@components/Table' import { EditableTable, makeColumn, makeActionHandler, defaultPagination, makeTimezoneColumn } from '@components/Table'
import { AdminDepositService } from '@api'
import { arrayOrDefault } from '@utils'
import { min1 } from '@utils/validationRules'
import { hasPermission } from '@utils/permissions' import { hasPermission } from '@utils/permissions'
import { min1 } from '@utils/validationRules'
import { arrayOrDefault } from '@utils'
import { AdminDepositService } from '@api'
export const coordsFixed = (coords) => coords && isFinite(coords) ? (+coords).toPrecision(10) : '-' export const coordsFixed = (coords) => coords && isFinite(coords) ? (+coords).toPrecision(10) : '-'
@ -19,7 +19,9 @@ const depositColumns = [
export const DepositController = memo(() => { export const DepositController = memo(() => {
const [deposits, setDeposits] = useState([]) const [deposits, setDeposits] = useState([])
const [filteredDeposits, setFilteredDeposits] = useState([])
const [showLoader, setShowLoader] = useState(false) const [showLoader, setShowLoader] = useState(false)
const [searchValue, setSearchValue] = useState('')
const updateTable = useCallback(() => invokeWebApiWrapperAsync( const updateTable = useCallback(() => invokeWebApiWrapperAsync(
async() => { async() => {
@ -33,27 +35,43 @@ export const DepositController = memo(() => {
useEffect(updateTable, [updateTable]) useEffect(updateTable, [updateTable])
const handlerProps = { useEffect(() => {
setFilteredDeposits(deposits.filter((deposit) => deposit && (!searchValue || [
deposit.caption ?? '',
deposit.latitude?.toString() ?? '',
deposit.longitude?.toString() ?? '',
].join(' ').toLowerCase().includes(searchValue.toLowerCase()))))
}, [deposits, searchValue])
const handlerProps = useMemo(() => ({
service: AdminDepositService, service: AdminDepositService,
setLoader: setShowLoader, setLoader: setShowLoader,
errorMsg: `Не удалось выполнить операцию`, errorMsg: `Не удалось выполнить операцию`,
onComplete: updateTable, onComplete: updateTable,
} }), [updateTable])
return ( return (
<LoaderPortal show={showLoader}> <>
<Input.Search
style={{ margin: '15px 0' }}
placeholder={'Введите текст для поиска...'}
onChange={(e) => setSearchValue(e.target.value)}
value={searchValue}
loading={showLoader}
/>
<EditableTable <EditableTable
size={'small'}
bordered bordered
dataSource={deposits} size={'small'}
loading={showLoader}
columns={depositColumns} columns={depositColumns}
dataSource={filteredDeposits}
pagination={defaultPagination} pagination={defaultPagination}
onRowAdd={hasPermission('AdminDeposit.edit') && makeActionHandler('insert', handlerProps, null, 'Добавление месторождения')} onRowAdd={hasPermission('AdminDeposit.edit') && makeActionHandler('insert', handlerProps, null, 'Добавление месторождения')}
onRowEdit={hasPermission('AdminDeposit.edit') && makeActionHandler('update', handlerProps, null, 'Редактирование месторождения')} onRowEdit={hasPermission('AdminDeposit.edit') && makeActionHandler('update', handlerProps, null, 'Редактирование месторождения')}
onRowDelete={hasPermission('AdminDeposit.delete') && makeActionHandler('delete', handlerProps, null, 'Удаление месторождения')} onRowDelete={hasPermission('AdminDeposit.delete') && makeActionHandler('delete', handlerProps, null, 'Удаление месторождения')}
tableName={'admin_deposit_controller'} tableName={'admin_deposit_controller'}
/> />
</LoaderPortal> </>
) )
}) })

View File

@ -1,4 +1,5 @@
import { memo, useCallback, useEffect, useState } from 'react' import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import { Input } from 'antd'
import { import {
EditableTable, EditableTable,
@ -6,7 +7,6 @@ import {
makeColumn, makeColumn,
makeStringSorter makeStringSorter
} from '@components/Table' } from '@components/Table'
import LoaderPortal from '@components/LoaderPortal'
import { invokeWebApiWrapperAsync } from '@components/factory' import { invokeWebApiWrapperAsync } from '@components/factory'
import { AdminPermissionService } from '@api' import { AdminPermissionService } from '@api'
import { arrayOrDefault } from '@utils' import { arrayOrDefault } from '@utils'
@ -27,8 +27,10 @@ const columns = [
] ]
export const PermissionController = memo(() => { export const PermissionController = memo(() => {
const [showLoader, setShowLoader] = useState(false)
const [permissions, setPermissions] = useState([]) const [permissions, setPermissions] = useState([])
const [filteredPermissions, setFilteredPermissions] = useState([])
const [showLoader, setShowLoader] = useState(false)
const [searchValue, setSearchValue] = useState('')
const updateTable = useCallback(async () => invokeWebApiWrapperAsync( const updateTable = useCallback(async () => invokeWebApiWrapperAsync(
async () => { async () => {
@ -42,27 +44,42 @@ export const PermissionController = memo(() => {
useEffect(() => updateTable(), [updateTable]) useEffect(() => updateTable(), [updateTable])
const handlerProps = { useEffect(() => {
setFilteredPermissions(permissions.filter((permission) => permission && (!searchValue || [
permission.name ?? '',
permission.description ?? '',
].join(' ').includes(searchValue.toLowerCase()))))
}, [permissions, searchValue])
const handlerProps = useMemo(() => ({
service: AdminPermissionService, service: AdminPermissionService,
setLoader: setShowLoader, setLoader: setShowLoader,
errorMsg: `Не удалось выполнить операцию`, errorMsg: `Не удалось выполнить операцию`,
onComplete: updateTable onComplete: updateTable
} }), [updateTable])
return ( return (
<LoaderPortal show={showLoader}> <>
<Input.Search
style={{ margin: '15px 0' }}
placeholder={'Введите текст для поиска...'}
onChange={(e) => setSearchValue(e.target.value)}
value={searchValue}
loading={showLoader}
/>
<EditableTable <EditableTable
bordered bordered
size={'small'} size={'small'}
columns={columns} columns={columns}
dataSource={permissions} loading={showLoader}
dataSource={filteredPermissions}
pagination={{ showSizeChanger: true }} pagination={{ showSizeChanger: true }}
onRowAdd={hasPermission('AdminPermission.edit') && makeActionHandler('insert', handlerProps, null, 'Добавление права')} onRowAdd={hasPermission('AdminPermission.edit') && makeActionHandler('insert', handlerProps, null, 'Добавление права')}
onRowEdit={hasPermission('AdminPermission.edit') && makeActionHandler('update', handlerProps, null, 'Редактирование права')} onRowEdit={hasPermission('AdminPermission.edit') && makeActionHandler('update', handlerProps, null, 'Редактирование права')}
onRowDelete={hasPermission('AdminPermission.delete') && makeActionHandler('delete', handlerProps, null, 'Удаление права')} onRowDelete={hasPermission('AdminPermission.delete') && makeActionHandler('delete', handlerProps, null, 'Удаление права')}
tableName={'admin_permission_controller'} tableName={'admin_permission_controller'}
/> />
</LoaderPortal> </>
) )
}) })

View File

@ -1,9 +1,9 @@
import { memo, useCallback, useEffect, useState } from 'react' import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import { Input } from 'antd'
import LoaderPortal from '@components/LoaderPortal'
import { PermissionView, RoleView } from '@components/views' import { PermissionView, RoleView } from '@components/views'
import { invokeWebApiWrapperAsync } from '@components/factory' import { invokeWebApiWrapperAsync } from '@components/factory'
import { EditableTable, makeActionHandler, makeColumn, makeTagColumn } from '@components/Table' import { EditableTable, makeActionHandler, makeTagColumn, makeTextColumn } from '@components/Table'
import { AdminPermissionService, AdminUserRoleService } from '@api' import { AdminPermissionService, AdminUserRoleService } from '@api'
import { arrayOrDefault } from '@utils' import { arrayOrDefault } from '@utils'
import { min1 } from '@utils/validationRules' import { min1 } from '@utils/validationRules'
@ -12,7 +12,9 @@ import { hasPermission } from '@utils/permissions'
export const RoleController = memo(() => { export const RoleController = memo(() => {
const [permissions, setPermissions] = useState([]) const [permissions, setPermissions] = useState([])
const [roles, setRoles] = useState([]) const [roles, setRoles] = useState([])
const [filteredRoles, setFilteredRoles] = useState([])
const [showLoader, setShowLoader] = useState(false) const [showLoader, setShowLoader] = useState(false)
const [searchValue, setSearchValue] = useState('')
const [columns, setColumns] = useState([]) const [columns, setColumns] = useState([])
const loadRoles = useCallback(async () => { const loadRoles = useCallback(async () => {
@ -22,7 +24,7 @@ export const RoleController = memo(() => {
useEffect(() => { useEffect(() => {
setColumns([ setColumns([
makeColumn('Название', 'caption', { width: 100, editable: true, formItemRules: min1 }), makeTextColumn('Название', 'caption', null, null, null, { width: 100, editable: true, formItemRules: min1 }),
makeTagColumn('Включённые роли', 'roles', roles, 'id', 'caption', { makeTagColumn('Включённые роли', 'roles', roles, 'id', 'caption', {
width: 400, width: 400,
editable: true, editable: true,
@ -47,7 +49,13 @@ export const RoleController = memo(() => {
'Получение списка ролей' 'Получение списка ролей'
), [loadRoles]) ), [loadRoles])
const handlerProps = { useEffect(() => {
setFilteredRoles(roles.filter((role) => role && (!searchValue ||
role.caption?.toLowerCase()?.includes(searchValue.toLowerCase())
)))
}, [roles, searchValue])
const handlerProps = useMemo(() => ({
service: AdminUserRoleService, service: AdminUserRoleService,
setLoader: setShowLoader, setLoader: setShowLoader,
errorMsg: `Не удалось выполнить операцию`, errorMsg: `Не удалось выполнить операцию`,
@ -57,21 +65,29 @@ export const RoleController = memo(() => {
`Не удалось загрузить список ролей`, `Не удалось загрузить список ролей`,
'Получение списка ролей' 'Получение списка ролей'
) )
} }), [loadRoles])
return ( return (
<LoaderPortal show={showLoader}> <>
<Input.Search
style={{ margin: '15px 0' }}
placeholder={'Введите текст для поиска...'}
onChange={(e) => setSearchValue(e.target.value)}
value={searchValue}
loading={showLoader}
/>
<EditableTable <EditableTable
bordered bordered
size={'small'} size={'small'}
columns={columns} columns={columns}
dataSource={roles} loading={showLoader}
dataSource={filteredRoles}
onRowAdd={hasPermission('AdminUserRole.edit') && makeActionHandler('insert', handlerProps, null, 'Добавление роли')} onRowAdd={hasPermission('AdminUserRole.edit') && makeActionHandler('insert', handlerProps, null, 'Добавление роли')}
onRowEdit={hasPermission('AdminUserRole.edit') && makeActionHandler('update', handlerProps, null, 'Редактирование роли')} onRowEdit={hasPermission('AdminUserRole.edit') && makeActionHandler('update', handlerProps, null, 'Редактирование роли')}
onRowDelete={hasPermission('AdminUserRole.delete') && makeActionHandler('delete', handlerProps, null, 'Удаление роли')} onRowDelete={hasPermission('AdminUserRole.delete') && makeActionHandler('delete', handlerProps, null, 'Удаление роли')}
tableName={'admin_role_controller'} tableName={'admin_role_controller'}
/> />
</LoaderPortal> </>
) )
}) })

View File

@ -1,4 +1,5 @@
import { memo, useEffect, useState } from 'react' import { memo, useEffect, useState } from 'react'
import { Input } from 'antd'
import { import {
defaultPagination, defaultPagination,
@ -8,7 +9,6 @@ import {
makeTextColumn, makeTextColumn,
Table Table
} from '@components/Table' } from '@components/Table'
import LoaderPortal from '@components/LoaderPortal'
import { invokeWebApiWrapperAsync } from '@components/factory' import { invokeWebApiWrapperAsync } from '@components/factory'
import { AdminTelemetryService } from '@api' import { AdminTelemetryService } from '@api'
import { arrayOrDefault } from '@utils' import { arrayOrDefault } from '@utils'
@ -31,7 +31,10 @@ const columns = [
export const TelemetryController = memo(() => { export const TelemetryController = memo(() => {
const [telemetryData, setTelemetryData] = useState([]) const [telemetryData, setTelemetryData] = useState([])
const [isLoading, setIsLoading] = useState(false) const [filteredTelemetryData, setFilteredTelemetryData] = useState([])
const [showLoader, setShowLoader] = useState(false)
const [searchValue, setSearchValue] = useState('')
useEffect(() => invokeWebApiWrapperAsync( useEffect(() => invokeWebApiWrapperAsync(
async () => { async () => {
@ -43,22 +46,46 @@ export const TelemetryController = memo(() => {
realWell: telemetry?.well?.caption, realWell: telemetry?.well?.caption,
}))) })))
}, },
setIsLoading, setShowLoader,
`Не удалось загрузить список телеметрии скважин`, `Не удалось загрузить список телеметрии скважин`,
'Полученик списка телеметрии скважин' 'Полученик списка телеметрии скважин'
), []) ), [])
useEffect(() => {
setFilteredTelemetryData(telemetryData.filter((telemetry) => telemetry && (!searchValue || [
telemetry.remoteUid ?? '',
telemetry.realWell ?? '',
telemetry.drillingStartDate ?? '',
telemetry.well ?? '',
telemetry.cluster ?? '',
telemetry.deposit ?? '',
telemetry.customer ?? '',
telemetry.comment ?? '',
telemetry.hmiVersion ?? '',
telemetry.saubPlcVersion ?? '',
telemetry.spinPlcVersion ?? '',
].join(' ').toLowerCase().includes(searchValue.toLowerCase()))))
}, [telemetryData, searchValue])
return ( return (
<LoaderPortal show={isLoading}> <>
<Input.Search
style={{ margin: '15px 0' }}
placeholder={'Введите текст для поиска...'}
onChange={(e) => setSearchValue(e.target.value)}
value={searchValue}
loading={showLoader}
/>
<Table <Table
size={'small'}
bordered bordered
size={'small'}
columns={columns} columns={columns}
dataSource={telemetryData} loading={showLoader}
pagination={defaultPagination} pagination={defaultPagination}
dataSource={filteredTelemetryData}
tableName={'admin_telemetry_controller'} tableName={'admin_telemetry_controller'}
/> />
</LoaderPortal> </>
) )
}) })

View File

@ -1,16 +1,12 @@
import { Select } from 'antd' import { Select } from 'antd'
import { memo, useEffect, useState } from 'react' import { memo, useMemo } from 'react'
export const RoleTag = memo(({ roles, value, onChange }) => { export const RoleTag = memo(({ roles, value, onChange }) => {
const [options, setOptions] = useState([]) const options = useMemo(() => roles.map((elm) => ({
useEffect(() => {
setOptions(roles.map((elm) => ({
key: Date.now(), key: Date.now(),
value: `${elm.caption}`, value: `${elm.caption}`,
label: elm.caption label: elm.caption
}))) })), [roles])
}, [roles])
return ( return (
<Select <Select

View File

@ -5,12 +5,11 @@ import { BehaviorSubject, debounceTime, distinctUntilChanged, filter, map } from
import { import {
EditableTable, EditableTable,
makeColumn,
makeSelectColumn, makeSelectColumn,
makeActionHandler, makeActionHandler,
makeStringSorter,
makeNumericSorter, makeNumericSorter,
defaultPagination defaultPagination,
makeTextColumn
} from '@components/Table' } from '@components/Table'
import { RoleView } from '@components/views' import { RoleView } from '@components/views'
import LoaderPortal from '@components/LoaderPortal' import LoaderPortal from '@components/LoaderPortal'
@ -38,7 +37,7 @@ export const UserController = memo(() => {
useEffect(() => invokeWebApiWrapperAsync( useEffect(() => invokeWebApiWrapperAsync(
async () => { async () => {
const filteredUsers = users.filter((user) => user && [ const filteredUsers = users.filter((user) => user && (!searchValue || [
user.login ?? '', user.login ?? '',
user.name ?? '', user.name ?? '',
user.surname ?? '', user.surname ?? '',
@ -47,7 +46,7 @@ export const UserController = memo(() => {
user.phone ?? '', user.phone ?? '',
user.position ?? '', user.position ?? '',
user.company?.caption ?? '', user.company?.caption ?? '',
].join(' ').toLowerCase().includes(searchValue)) ].join(' ').toLowerCase().includes(searchValue.toLowerCase())))
setFilteredUsers(filteredUsers) setFilteredUsers(filteredUsers)
}, },
setIsSearching, setIsSearching,
@ -106,8 +105,14 @@ export const UserController = memo(() => {
const filters = makeTextFilters(users, ['surname', 'name', 'patronymic', 'email']) const filters = makeTextFilters(users, ['surname', 'name', 'patronymic', 'email'])
const roleFilters = [{ text: 'Без роли', value: null }, ...roles.map((role) => ({ text: role.caption, value: role.caption }))] const roleFilters = [{ text: 'Без роли', value: null }, ...roles.map((role) => ({ text: role.caption, value: role.caption }))]
const rolesRender = (item) => item?.map((elm) => (
<Tag key={elm} color={'blue'}>
<RoleView role={roles.find((role) => role.caption === elm)} />
</Tag>
)) ?? '-'
setColumns([ setColumns([
makeColumn('Логин', 'login', { makeTextColumn('Логин', 'login', null, null, null, {
editable: true, editable: true,
formItemRules: [ formItemRules: [
{ required: true }, { required: true },
@ -121,59 +126,40 @@ export const UserController = memo(() => {
// }) // })
// TODO: Для проверки уникальности логина необходимо исключить из выборки логин выбранного пользователя // TODO: Для проверки уникальности логина необходимо исключить из выборки логин выбранного пользователя
], ],
sorter: makeStringSorter('login'),
}), }),
makeColumn('Фамилия', 'surname', { makeTextColumn('Фамилия', 'surname', filters.surname, null, null, {
editable: true, editable: true,
formItemRules: [{ required: true }, ...nameRules], formItemRules: [{ required: true }, ...nameRules],
sorter: makeStringSorter('surname'),
filters: filters.surname,
filterSearch: true, filterSearch: true,
onFilter: makeTextOnFilter('surname'), onFilter: makeTextOnFilter('surname'),
}), }),
makeColumn('Имя', 'name', { makeTextColumn('Имя', 'name', filters.name, null, null, {
editable: true, editable: true,
formItemRules: nameRules, formItemRules: nameRules,
sorter: makeStringSorter('name'),
filters: filters.name,
filterSearch: true, filterSearch: true,
onFilter: makeTextOnFilter('name'), onFilter: makeTextOnFilter('name'),
}), }),
makeColumn('Отчество', 'patronymic', { makeTextColumn('Отчество', 'patronymic', filters.partonymic, null, null, {
editable: true, editable: true,
formItemRules: nameRules, formItemRules: nameRules,
sorter: makeStringSorter('patronymic'),
filters: filters.patronymic,
filterSearch: true, filterSearch: true,
onFilter: makeTextOnFilter('patronymic'), onFilter: makeTextOnFilter('patronymic'),
}), }),
makeColumn('E-mail', 'email', { makeTextColumn('E-mail', 'email', filters.email, null, null, {
editable: true, editable: true,
formItemRules: [{ required: true }, ...emailRules], formItemRules: [{ required: true }, ...emailRules],
sorter: makeStringSorter('email'),
filters: filters.email,
filterSearch: true, filterSearch: true,
onFilter: makeTextOnFilter('email'), onFilter: makeTextOnFilter('email'),
}), }),
makeColumn('Номер телефона', 'phone', { makeTextColumn('Номер телефона', 'phone', null, null, null, {
editable: true, editable: true,
formItemRules: phoneRules, formItemRules: phoneRules,
sorter: makeStringSorter('phone'),
}), }),
makeColumn('Должность', 'position', { makeTextColumn('Должность', 'position', null, null, null, { editable: true }),
editable: true, makeTextColumn('Роли', 'roleNames', roleFilters, null, rolesRender, {
sorter: makeStringSorter('position'),
}),
makeColumn('Роли', 'roleNames', {
editable: true, editable: true,
input: <RoleTag roles={roles} />, input: <RoleTag roles={roles} />,
filters: roleFilters,
onFilter: makeArrayOnFilter('roleNames'), onFilter: makeArrayOnFilter('roleNames'),
render: (item) => item?.map((elm) => (
<Tag key={elm} color={'blue'}>
<RoleView role={roles.find((role) => role.caption === elm)} />
</Tag>
)) ?? '-'
}), }),
makeSelectColumn('Компания', 'idCompany', companies, '--', { makeSelectColumn('Компания', 'idCompany', companies, '--', {
editable: true, editable: true,

View File

@ -1,6 +1,6 @@
import { memo, useEffect, useState } from 'react' import { memo, useEffect, useState } from 'react'
import { Input } from 'antd'
import LoaderPortal from '@components/LoaderPortal'
import { invokeWebApiWrapperAsync } from '@components/factory' import { invokeWebApiWrapperAsync } from '@components/factory'
import { defaultPagination, makeColumn, makeDateSorter, makeStringSorter, Table } from '@components/Table' import { defaultPagination, makeColumn, makeDateSorter, makeStringSorter, Table } from '@components/Table'
import { RequestTrackerService } from '@api' import { RequestTrackerService } from '@api'
@ -19,7 +19,9 @@ const columns = [
export const VisitLog = memo(() => { export const VisitLog = memo(() => {
const [logData, setLogData] = useState([]) const [logData, setLogData] = useState([])
const [isLoading, setIsLoading] = useState(false) const [filteredLogData, setFilteredLogData] = useState([])
const [showLoader, setShowLoader] = useState(false)
const [searchValue, setSearchValue] = useState('')
useEffect(() => invokeWebApiWrapperAsync( useEffect(() => invokeWebApiWrapperAsync(
async () => { async () => {
@ -27,23 +29,38 @@ export const VisitLog = memo(() => {
logData.forEach((log) => log.key = `${log.login}${log.ip}`) logData.forEach((log) => log.key = `${log.login}${log.ip}`)
setLogData(logData) setLogData(logData)
}, },
setIsLoading, setShowLoader,
`Не удалось загрузить список последних посещений пользователей`, `Не удалось загрузить список последних посещений пользователей`,
'Получение списка последних посещений' 'Получение списка последних посещений'
), []) ), [])
useEffect(() => {
setFilteredLogData(logData.filter((data) => data && (!searchValue || [
data.login ?? '',
data.ip ?? '',
data.lastDate ?? '',
].join(' ').toLowerCase().includes(searchValue.toLowerCase()))))
}, [logData, searchValue])
return ( return (
<LoaderPortal show={isLoading}> <>
<Input.Search
style={{ margin: '15px 0' }}
placeholder={'Введите текст для поиска...'}
onChange={(e) => setSearchValue(e.target.value)}
value={searchValue}
loading={showLoader}
/>
<Table <Table
size={'small'}
bordered bordered
size={'small'}
columns={columns} columns={columns}
dataSource={logData} loading={showLoader}
dataSource={filteredLogData}
pagination={defaultPagination} pagination={defaultPagination}
tableName={'visit_log'} tableName={'visit_log'}
/> />
</LoaderPortal> </>
) )
}) })

View File

@ -1,6 +1,6 @@
import { Button } from 'antd' import { Button, Input } from 'antd'
import { CopyOutlined } from '@ant-design/icons' import { CopyOutlined } from '@ant-design/icons'
import { memo, useEffect, useState } from 'react' import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import { import {
AdminClusterService, AdminClusterService,
@ -19,7 +19,6 @@ import {
defaultPagination, defaultPagination,
makeTimezoneColumn, makeTimezoneColumn,
} from '@components/Table' } from '@components/Table'
import LoaderPortal from '@components/LoaderPortal'
import { invokeWebApiWrapperAsync } from '@components/factory' import { invokeWebApiWrapperAsync } from '@components/factory'
import { TelemetryView, CompanyView } from '@components/views' import { TelemetryView, CompanyView } from '@components/views'
import { hasPermission } from '@utils/permissions' import { hasPermission } from '@utils/permissions'
@ -43,9 +42,12 @@ const recordParser = (record) => ({
export const WellController = memo(() => { export const WellController = memo(() => {
const [columns, setColumns] = useState([]) const [columns, setColumns] = useState([])
const [wells, setWells] = useState([]) const [wells, setWells] = useState([])
const [filteredWells, setFilteredWells] = useState([])
const [showLoader, setShowLoader] = useState(false) const [showLoader, setShowLoader] = useState(false)
const [searchValue, setSearchValue] = useState('')
const updateTable = async () => invokeWebApiWrapperAsync(
const updateTable = useCallback(async () => invokeWebApiWrapperAsync(
async () => { async () => {
const wells = await AdminWellService.getAll() const wells = await AdminWellService.getAll()
setWells(arrayOrDefault(wells)) setWells(arrayOrDefault(wells))
@ -53,11 +55,11 @@ export const WellController = memo(() => {
setShowLoader, setShowLoader,
`Не удалось загрузить список скважин`, `Не удалось загрузить список скважин`,
'Получение списка скважин' 'Получение списка скважин'
) ), [])
const duplicateWell = (well) => { const duplicateWell = useCallback((well) => {
// TODO: Метод дубликации скважины // TODO: Метод дубликации скважины
} }, [])
const addititonalButtons = memo((record, editingKey) => ( const addititonalButtons = memo((record, editingKey) => (
<Button <Button
@ -112,22 +114,38 @@ export const WellController = memo(() => {
setShowLoader, setShowLoader,
`Не удалось загрузить список кустов`, `Не удалось загрузить список кустов`,
'Получение списка кустов' 'Получение списка кустов'
), []) ), [updateTable])
const handlerProps = { useEffect(() => {
setFilteredWells(wells.filter((well) => well && (!searchValue || [
well.caption ?? '',
well.latitude?.toString() ?? '',
well.longitude?.toString() ?? '',
].join(' ').toLowerCase().includes(searchValue.toLowerCase()))))
}, [wells, searchValue])
const handlerProps = useMemo(() => ({
service: AdminWellService, service: AdminWellService,
setLoader: setShowLoader, setLoader: setShowLoader,
errorMsg: `Не удалось выполнить операцию`, errorMsg: `Не удалось выполнить операцию`,
onComplete: updateTable onComplete: updateTable
} }), [updateTable])
return ( return (
<LoaderPortal show={showLoader}> <>
<Input.Search
style={{ margin: '15px 0' }}
placeholder={'Введите текст для поиска...'}
onChange={(e) => setSearchValue(e.target.value)}
value={searchValue}
loading={showLoader}
/>
<EditableTable <EditableTable
size={'small'} size={'small'}
bordered bordered
columns={columns} columns={columns}
dataSource={wells} loading={showLoader}
dataSource={filteredWells}
pagination={defaultPagination} pagination={defaultPagination}
onRowAdd={hasPermission('AdminWell.edit') && makeActionHandler('insert', handlerProps, recordParser, 'Добавление скважины')} onRowAdd={hasPermission('AdminWell.edit') && makeActionHandler('insert', handlerProps, recordParser, 'Добавление скважины')}
onRowEdit={hasPermission('AdminWell.edit') && makeActionHandler('update', handlerProps, recordParser, 'Редактирование скважины')} onRowEdit={hasPermission('AdminWell.edit') && makeActionHandler('update', handlerProps, recordParser, 'Редактирование скважины')}
@ -136,7 +154,7 @@ export const WellController = memo(() => {
buttonsWidth={95} buttonsWidth={95}
tableName={'admin_well_controller'} tableName={'admin_well_controller'}
/> />
</LoaderPortal> </>
) )
}) })

View File

@ -4,7 +4,7 @@ import { FilterOutlined } from '@ant-design/icons'
import LoaderPortal from '@components/LoaderPortal' import LoaderPortal from '@components/LoaderPortal'
import { invokeWebApiWrapperAsync } from '@components/factory' import { invokeWebApiWrapperAsync } from '@components/factory'
import { makeDateColumn, makeNumericColumn, makeTextColumn, Table } from '@components/Table' import { makeDateColumn, makeNumericColumn, makeNumericRender, makeTextColumn, Table } from '@components/Table'
import '@styles/tvd.less' import '@styles/tvd.less'
@ -12,7 +12,7 @@ export const columns = [
makeTextColumn('Конструкция секции', 'wellSectionTypeName', null, null, null, { width: 140 }), makeTextColumn('Конструкция секции', 'wellSectionTypeName', null, null, null, { width: 140 }),
makeNumericColumn('Глубина', 'depth', null, null, null, 80), makeNumericColumn('Глубина', 'depth', null, null, null, 80),
makeDateColumn('Дата начала', 'date', false, undefined, { width: 90 }), makeDateColumn('Дата начала', 'date', false, undefined, { width: 90 }),
makeNumericColumn('Длительность (ч)', 'durationHours', null, null, null, 120), makeNumericColumn('Длительность (ч)', 'durationHours', null, null, makeNumericRender(2), 120),
makeTextColumn('Доп. инфо', 'categoryInfo', null, null, null), makeTextColumn('Доп. инфо', 'categoryInfo', null, null, null),
makeTextColumn('Комментарий', 'comment'), makeTextColumn('Комментарий', 'comment'),
] ]