forked from ddrilling/asb_cloud_front
* Вывод ошибки о существовании рапорта исправлен
* Добавлены константы для mime-типов * Исправлена ошибка отправки файлов на сервер * Добавлен проп mimeType в UploadForm для контроля типов загружаемых файлов * Добавлена проверка необходимости обновления страница после закрытия окна редактирования части ПБ * Добавлен тип сообщения для notify * Изменён формат даты в окне суточного рапорта * Добавлен вывод сообщения исключения в редактировании суточного рапорта
This commit is contained in:
parent
3912e9b308
commit
12a6d96a95
@ -1,15 +1,17 @@
|
||||
import { memo, useCallback, useState } from 'react'
|
||||
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { Upload, Button } from 'antd'
|
||||
import { UploadOutlined } from '@ant-design/icons'
|
||||
import { UploadFile } from 'antd/lib/upload/interface'
|
||||
import { RcFile } from 'antd/lib/upload'
|
||||
|
||||
import { upload } from './factory'
|
||||
import { notify, upload } from './factory'
|
||||
import { ErrorFetch } from './ErrorFetch'
|
||||
|
||||
export type UploadFormProps = {
|
||||
url: string
|
||||
disabled?: boolean
|
||||
accept?: string
|
||||
mimeTypes?: string | string[]
|
||||
style?: CSSStyleSheet
|
||||
formData: FormData
|
||||
onUploadStart?: () => void
|
||||
@ -18,14 +20,25 @@ export type UploadFormProps = {
|
||||
onUploadError?: (error: unknown) => void
|
||||
}
|
||||
|
||||
export const UploadForm = memo<UploadFormProps>(({ url, disabled, accept, style, formData, onUploadStart, onUploadSuccess, onUploadComplete, onUploadError }) => {
|
||||
export const UploadForm = memo<UploadFormProps>(({ url, disabled, style, formData, mimeTypes, onUploadStart, onUploadSuccess, onUploadComplete, onUploadError }) => {
|
||||
const [fileList, setfileList] = useState<UploadFile<any>[]>([])
|
||||
|
||||
const checkMimeTypes = useCallback((file: RcFile) => {
|
||||
const isAccepted = !mimeTypes || mimeTypes.includes(file.type)
|
||||
if (isAccepted) return false
|
||||
notify(`"${file.name}" является файлом неподходящего типа`, 'error')
|
||||
return Upload.LIST_IGNORE
|
||||
}, [mimeTypes])
|
||||
|
||||
const accept = useMemo(() => Array.isArray(mimeTypes) ? mimeTypes.join(',') : mimeTypes, [mimeTypes])
|
||||
|
||||
useEffect(() => console.log(fileList), [fileList])
|
||||
|
||||
const handleFileSend = useCallback(async () => {
|
||||
onUploadStart?.()
|
||||
try {
|
||||
const formDataLocal = new FormData()
|
||||
fileList.forEach((val) => formDataLocal.append('files', String(val.originFileObj)))
|
||||
fileList.forEach((val) => formDataLocal.append('files', val.originFileObj as Blob))
|
||||
|
||||
if(formData)
|
||||
for(const propName in formData)
|
||||
@ -58,6 +71,7 @@ export const UploadForm = memo<UploadFormProps>(({ url, disabled, accept, style,
|
||||
disabled={disabled}
|
||||
fileList={fileList}
|
||||
onChange={(props) => setfileList(props.fileList)}
|
||||
beforeUpload={checkMimeTypes}
|
||||
>
|
||||
<Button disabled={disabled} icon={<UploadOutlined/>}>Загрузить файл</Button>
|
||||
</Upload>
|
||||
|
@ -11,12 +11,14 @@ const notificationTypeDictionary = new Map([
|
||||
['open' , { notifyInstance: notification.info , caption: '' }],
|
||||
])
|
||||
|
||||
export type NotifyType = 'error' | 'warning' | 'info'
|
||||
|
||||
/**
|
||||
* Вызов оповещений всплывающим окошком.
|
||||
* @param body string или ReactNode
|
||||
* @param notifyType для параметра типа. Допустимые значение 'error', 'warning', 'info'
|
||||
*/
|
||||
export const notify = (body: ReactNode, notifyType: string = 'info', other?: any) => {
|
||||
export const notify = (body: ReactNode, notifyType: NotifyType = 'info', other?: any) => {
|
||||
if (!body) return
|
||||
|
||||
const instance = notificationTypeDictionary.get(notifyType) ??
|
||||
|
@ -31,7 +31,7 @@ const columns = [
|
||||
makeColumn('Компания', 'company', { render: (_, record) => <CompanyView company={record?.author?.company}/> })
|
||||
]
|
||||
|
||||
export const DocumentsTemplate = ({ idCategory, idWell: wellId, accept, headerChild, customColumns, beforeTable, onChange, tableName }) => {
|
||||
export const DocumentsTemplate = ({ idCategory, idWell: wellId, mimeTypes, headerChild, customColumns, beforeTable, onChange, tableName }) => {
|
||||
const [page, setPage] = useState(1)
|
||||
const [filterDataRange, setFilterDataRange] = useState([])
|
||||
const [filterCompanyName, setFilterCompanyName] = useState([])
|
||||
@ -134,7 +134,7 @@ export const DocumentsTemplate = ({ idCategory, idWell: wellId, accept, headerCh
|
||||
<span>Загрузка</span>
|
||||
<UploadForm
|
||||
url={uploadUrl}
|
||||
accept={accept}
|
||||
mimeTypes={mimeTypes}
|
||||
onUploadStart={() => setShowLoader(true)}
|
||||
onUploadComplete={update}
|
||||
/>
|
||||
|
@ -28,9 +28,12 @@ export const CategoryEditor = memo(({ visible, category, onClosed }) => {
|
||||
const [showLoader, setShowLoader] = useState(false)
|
||||
const [searchValue, setSearchValue] = useState('')
|
||||
const [subject, setSubject] = useState(null)
|
||||
const [needUpdate, setNeedUpdate] = useState(false)
|
||||
|
||||
const idWell = useContext(IdWellContext)
|
||||
|
||||
useEffect(() => visible && setNeedUpdate(false), [visible])
|
||||
|
||||
useEffect(() => invokeWebApiWrapperAsync(
|
||||
async () => {
|
||||
const filteredUsers = users.filter(({ user }) => user && [
|
||||
@ -108,6 +111,7 @@ export const CategoryEditor = memo(({ visible, category, onClosed }) => {
|
||||
prevUsers[userIdx].status = status
|
||||
return [...prevUsers]
|
||||
})
|
||||
setNeedUpdate(true)
|
||||
},
|
||||
setShowLoader,
|
||||
<>
|
||||
@ -138,9 +142,9 @@ export const CategoryEditor = memo(({ visible, category, onClosed }) => {
|
||||
const onSearchTextChange = useCallback((e) => subject?.next(e?.target?.value), [subject])
|
||||
|
||||
const onModalClosed = useCallback(() => {
|
||||
onClosed?.()
|
||||
onClosed?.(needUpdate)
|
||||
calcUsers()
|
||||
}, [onClosed, calcUsers])
|
||||
}, [onClosed, calcUsers, needUpdate])
|
||||
|
||||
return (
|
||||
<Modal
|
||||
|
@ -14,7 +14,7 @@ import LoaderPortal from '@components/LoaderPortal'
|
||||
import Poprompt from '@components/selectors/Poprompt'
|
||||
import { formatBytes, invokeWebApiWrapperAsync, notify } from '@components/factory'
|
||||
import { DrillingProgramService } from '@api'
|
||||
import { formatDate } from '@utils'
|
||||
import { formatDate, MimeTypes } from '@utils'
|
||||
|
||||
import MarksCard from './MarksCard'
|
||||
|
||||
@ -124,6 +124,7 @@ export const CategoryRender = memo(({ partData, onUpdate, onEdit, onHistory, set
|
||||
{permissionToUpload && (
|
||||
<UploadForm
|
||||
url={uploadUrl}
|
||||
mimeTypes={MimeTypes.XLSX}
|
||||
style={{ margin: '5px 0 10px 0' }}
|
||||
onUploadStart={() => setIsUploading(true)}
|
||||
onUploadComplete={onUploadComplete}
|
||||
|
@ -8,9 +8,9 @@ import {
|
||||
ReloadOutlined,
|
||||
WarningOutlined,
|
||||
} from '@ant-design/icons'
|
||||
import { memo, useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
||||
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import { IdWellContext } from '@asb/context'
|
||||
import { useIdWell } from '@asb/context'
|
||||
import LoaderPortal from '@components/LoaderPortal'
|
||||
import { downloadFile, formatBytes, invokeWebApiWrapperAsync } from '@components/factory'
|
||||
import { arrayOrDefault, formatDate } from '@utils'
|
||||
@ -23,20 +23,22 @@ import CategoryHistory from './CategoryHistory'
|
||||
|
||||
import '@styles/drilling_program.less'
|
||||
|
||||
const idStateNotInitialized = 0
|
||||
const idStateApproving = 1
|
||||
const idStateCreating = 2
|
||||
const idStateReady = 3
|
||||
const idStateError = 4
|
||||
const idStateUnknown = -1
|
||||
const ID_STATE = {
|
||||
NotInitialized: 0,
|
||||
Approving: 1,
|
||||
Creating: 2,
|
||||
Ready: 3,
|
||||
Error: 4,
|
||||
Unknown: -1,
|
||||
}
|
||||
|
||||
const stateString = {
|
||||
[idStateNotInitialized]: { icon: CloseOutlined, text: 'Не настроена' },
|
||||
[idStateApproving]: { icon: AuditOutlined, text: 'Согласовывается' },
|
||||
[idStateCreating]: { icon: LoadingOutlined, text: 'Формируется' },
|
||||
[idStateReady]: { icon: CheckOutlined, text: 'Сформирована' },
|
||||
[idStateError]: { icon: WarningOutlined, text: 'Ошибка формирования' },
|
||||
[idStateUnknown]: { icon: WarningOutlined, text: 'Неизвестно' },
|
||||
const STATE_STRING = {
|
||||
[ID_STATE.NotInitialized]: { icon: CloseOutlined, text: 'Не настроена' },
|
||||
[ID_STATE.Approving]: { icon: AuditOutlined, text: 'Согласовывается' },
|
||||
[ID_STATE.Creating]: { icon: LoadingOutlined, text: 'Формируется' },
|
||||
[ID_STATE.Ready]: { icon: CheckOutlined, text: 'Сформирована' },
|
||||
[ID_STATE.Error]: { icon: WarningOutlined, text: 'Ошибка формирования' },
|
||||
[ID_STATE.Unknown]: { icon: WarningOutlined, text: 'Неизвестно' },
|
||||
}
|
||||
|
||||
export const DrillingProgram = memo(() => {
|
||||
@ -47,7 +49,7 @@ export const DrillingProgram = memo(() => {
|
||||
const [categories, setCategories] = useState([])
|
||||
const [data, setData] = useState({})
|
||||
|
||||
const idWell = useContext(IdWellContext)
|
||||
const idWell = useIdWell()
|
||||
|
||||
const {
|
||||
idState,
|
||||
@ -57,8 +59,8 @@ export const DrillingProgram = memo(() => {
|
||||
error,
|
||||
} = useMemo(() => data, [data])
|
||||
|
||||
const stateId = useMemo(() => idState ?? idStateUnknown, [idState])
|
||||
const state = useMemo(() => stateString[stateId], [stateId])
|
||||
const stateId = useMemo(() => idState ?? ID_STATE.Unknown, [idState])
|
||||
const state = useMemo(() => STATE_STRING[stateId], [stateId])
|
||||
const StateIcon = useMemo(() => state.icon, [state?.icon])
|
||||
|
||||
const updateData = useCallback(async () => await invokeWebApiWrapperAsync(
|
||||
@ -89,8 +91,9 @@ export const DrillingProgram = memo(() => {
|
||||
setHistoryVisible(!!catId)
|
||||
}, [])
|
||||
|
||||
const onEditorClosed = useCallback(() => {
|
||||
const onEditorClosed = useCallback((needUpdate) => {
|
||||
setEditorVisible(false)
|
||||
if (needUpdate)
|
||||
updateData()
|
||||
}, [updateData])
|
||||
|
||||
@ -107,7 +110,7 @@ export const DrillingProgram = memo(() => {
|
||||
)}
|
||||
</div>
|
||||
<div className={'program_content'}>
|
||||
{stateId === idStateReady ? (
|
||||
{stateId === ID_STATE.Ready ? (
|
||||
<>
|
||||
<Button
|
||||
type={'link'}
|
||||
@ -120,7 +123,7 @@ export const DrillingProgram = memo(() => {
|
||||
<div className={'m-10'}>Размер: {formatBytes(program?.size)}</div>
|
||||
<div className={'m-10'}>Сформирован: {formatDate(program?.uploadDate)}</div>
|
||||
</>
|
||||
) : stateId === idStateError ? (
|
||||
) : stateId === ID_STATE.Error ? (
|
||||
<>
|
||||
<h3 className={'program_status error'}>
|
||||
<StateIcon className={'m-10'} />
|
||||
|
@ -168,11 +168,11 @@ export const ReportEditor = memo(({ visible, data, onDone, onCancel, checkIsDate
|
||||
if (data) return
|
||||
const newData = await DailyReportService.getOrGenerate(idWell, date.format('YYYY-MM-DD') + 'Z')
|
||||
if (checkIsDateBusy(moment(newData.reportDate)))
|
||||
throw 'Рапорт на данную дату уже существует'
|
||||
throw new Error('Рапорт на данную дату уже существует')
|
||||
setFields(newData)
|
||||
},
|
||||
setIsLoading,
|
||||
'Не удалось загрузить автозаполняемые данные для нового рапорта',
|
||||
(e) => `Не удалось загрузить автозаполняемые данные для нового рапорта: ${e}`,
|
||||
'Получение автозаполняемых данных суточного рапорта',
|
||||
), [idWell, data, setFields, checkIsDateBusy])
|
||||
|
||||
|
@ -36,7 +36,7 @@ export const DailyReport = memo(() => {
|
||||
const checkIsDateBusy = useCallback((current) => current.isAfter(moment(), 'day') || data.some((row) => moment(row.reportDate).isSame(current, 'day')), [data])
|
||||
|
||||
const columns = useMemo(() => [
|
||||
makeDateColumn('Дата', 'reportDate', undefined, 'YYYY.MM.DD', { width: 300 }),
|
||||
makeDateColumn('Дата', 'reportDate', undefined, 'DD.MM.YYYY', { width: 300 }),
|
||||
makeColumn('', '', { width: 200, render: (_, report) => (
|
||||
<>
|
||||
<Button
|
||||
|
@ -1,6 +1,8 @@
|
||||
export { isRawDate, formatDate, defaultFormat, periodToString } from './datetime'
|
||||
export type { RawDate, timeInS } from './datetime'
|
||||
|
||||
export { MimeTypes } from './mimeTypes'
|
||||
|
||||
export const headerHeight: number = 64
|
||||
|
||||
export const mainFrameSize = () => ({
|
||||
|
34
src/utils/mimeTypes.ts
Normal file
34
src/utils/mimeTypes.ts
Normal file
@ -0,0 +1,34 @@
|
||||
export const MimeTypes = {
|
||||
BMP: 'image/bmp',
|
||||
CSV: 'text/csv',
|
||||
CSV1: 'application/csv',
|
||||
DOC: 'application/msword',
|
||||
DOCM: 'application/vnd.ms-word.document.macroEnabled.12',
|
||||
DOCX: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
DOTM: 'application/vnd.ms-word.template.macroEnabled.12',
|
||||
DOTX: 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
|
||||
GIF: 'image/gif',
|
||||
HTML: 'text/html',
|
||||
JPEG: 'image/jpeg',
|
||||
JPG: 'image/jpeg',
|
||||
JSON: 'application/json',
|
||||
PDF: 'application/pdf',
|
||||
PNG: 'image/png',
|
||||
POTM: 'application/vnd.ms-powerpoint.template.macroEnabled.12',
|
||||
POTX: 'application/vnd.openxmlformats-officedocument.presentationml.template',
|
||||
PPAM: 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
|
||||
PPS: 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
|
||||
PPSM: 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
|
||||
PPSX: 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
|
||||
PPT: 'application/vnd.ms-powerpoint',
|
||||
PPTM: 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
|
||||
PPTX: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
RTF: 'application/rtf',
|
||||
RTF2: 'text/rtf',
|
||||
TXT: 'text/plain',
|
||||
XLSB: 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
|
||||
XLSM: 'application/vnd.ms-excel.sheet.macroEnabled.12',
|
||||
XLSX: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
}
|
||||
|
||||
export default MimeTypes
|
Loading…
Reference in New Issue
Block a user