diff --git a/src/components/UploadFileForm.jsx b/src/components/UploadFileForm.jsx
new file mode 100644
index 0000000..831ff87
--- /dev/null
+++ b/src/components/UploadFileForm.jsx
@@ -0,0 +1,56 @@
+import { Form, Upload, Button} from 'antd'
+import { UploadOutlined} from '@ant-design/icons'
+import { useState } from 'react'
+import { upload } from './factory'
+
+export default function UploadFileForm({url, onUploadStart, onUploadComplete, onUploadError}) {
+ const [isSubmitButtonEnabled, setSubmitButtonEnabled] = useState(false)
+ const [form] = Form.useForm();
+
+ const handleFileSend = async (values) => {
+ if(onUploadStart)
+ onUploadStart()
+ try {
+ const values = await form.validateFields();
+ const formData = new FormData()
+ values.documentFile.fileList.forEach((val) => {
+ formData.append("files", val.originFileObj);
+ });
+ await upload(url, formData)
+ } catch(error) {
+ if(onUploadError)
+ onUploadError(error)
+ } finally {
+ form.resetFields()
+ if(onUploadComplete)
+ onUploadComplete()
+ }
+ }
+
+ return(
+
+ setSubmitButtonEnabled(props.fileList.length > 0)}>
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/modalWindows/DocumentCreationForm.jsx b/src/components/modalWindows/DocumentCreationForm.jsx
deleted file mode 100644
index 53a6e7f..0000000
--- a/src/components/modalWindows/DocumentCreationForm.jsx
+++ /dev/null
@@ -1,108 +0,0 @@
-import { Form, Upload, Button } from 'antd'
-import { InboxOutlined } from '@ant-design/icons'
-import {useState} from "react"
-import {useParams} from 'react-router-dom'
-
-const { Dragger } = Upload;
-
-export default function DocumentCreationForm({selectedFileCategory, closeModalHandler}){
-
- let {id} = useParams()
-
- const [form] = Form.useForm();
-
- const [selectedFiles, setSelectedFiles] = useState([])
-
- const onFinish = (form) => {
- form
- .validateFields()
- .then(values => {
- var fileList = values.documentFile.fileList
-
- if (fileList.length > 0) {
- const formData = new FormData();
-
- fileList.forEach(val => {
- formData.append('files', val.originFileObj)
- })
-
- fetch(`/api/files/${id}/files?idCategory=${selectedFileCategory}&idUser=${localStorage['userId']}`, {
- headers: {
- Authorization: 'Bearer ' + localStorage['token']
- },
- method: 'POST',
- body: formData
- })
-
- form.resetFields();
- closeModalHandler()
- }
- }).catch(info => {
- console.log('Validate Failed:', info);
- });
- }
-
- const submitFileFormProps = {
- progress: {
- strokeColor: {
- '0%': '#108ee9',
- '100%': '#87d068',
- },
- strokeWidth: 3,
- format: percent => `${parseFloat(percent.toFixed(2))}%`,
- },
- multiple: true,
- onChange({ file, fileList }) {
- if (file.status !== 'uploading') {
- setSelectedFiles(fileList)
- }
- }
- }
-
- return (
-
-
-
-
-
- Кликните или перенесите сюда файлы
-
- Возможна загрузка как одного файла, так и нескольких.
-
-
-
-
-
-
-
-
-
-
-
- )
-}
\ No newline at end of file
diff --git a/src/pages/Documents.jsx b/src/pages/Documents.jsx
deleted file mode 100644
index e4e6602..0000000
--- a/src/pages/Documents.jsx
+++ /dev/null
@@ -1,183 +0,0 @@
-import {useState, useEffect} from "react"
-import {Table, DatePicker, Button, Modal, ConfigProvider} from 'antd'
-import { UploadOutlined } from '@ant-design/icons'
-import locale from "antd/lib/locale/ru_RU"
-import moment from 'moment'
-import DocumentCreationForm from '../components/modalWindows/DocumentCreationForm'
-import { FileService } from '../services/api'
-import notify from '../components/notify'
-import LoaderPortal from '../components/LoaderPortal'
-
-const pageSize = 12
-const {RangePicker} = DatePicker;
-
-export default function Documents({selectedFileCategory, idWell}) {
- const [page, setPage] = useState(1)
- const [range, setRange] = useState([])
- const [pagination, setPagination] = useState(null)
- const [files, setFiles] = useState([])
- const [isModalVisible, setIsModalVisible] = useState(false)
- const [isTableUpdating, setTableUpdating] = useState(false)
-
- const [showLoader, setShowLoader] = useState(false)
-
- const handleFileNameCLick = async (event, row) => {
- const element = event.target
-
- if(!element.href.length) {
- try {
- setShowLoader(true)
-
- await fetch(`/api/files/${idWell}/${row.id}`, {
- headers: {
- Authorization: 'Bearer ' + localStorage['token']
- }
- })
- .then(async (response) => {
- const blob = await response.blob();
-
- let reader = new FileReader();
- reader.readAsDataURL(blob);
- reader.onload = function (e) {
- element.href = e.target.result
- element.click()
- };
- setShowLoader(false)
- });
- } catch (error) {
- notify(`Не удалось скачать файл ${row}`, 'error')
- console.log(error)
- }
- }
- }
-
- const columns = [
- {
- title: 'Документ',
- key: 'document',
- dataIndex: 'name',
- render: (name, row) =>
-
- },
- {
- title: 'Дата загрузки',
- key: 'uploadDate',
- dataIndex: 'uploadDate',
- render: (item) => moment.utc(item).local().format('DD MMM YYYY, HH:mm:ss')
- },
- {
- title: 'Ф.И.О.',
- key: 'userName',
- dataIndex: 'userName',
- }
- ];
-
- const openModal = () => {
- setIsModalVisible(true)
- }
-
- const closeModal = () => {
- setIsModalVisible(false)
- }
-
- const onChangeRange = (range) => {
- setRange(range)
- }
-
- useEffect(() => {
- const GetDocuments = async () => {
- setShowLoader(true)
-
- try {
- let begin = null
- let end = null
- if (range?.length > 1) {
- begin = range[0].toISOString()
- end = range[1].toISOString()
- }
-
- await FileService.getFilesInfo(
- `${idWell}`,
- (page - 1) * pageSize,
- pageSize,
- selectedFileCategory,
- begin,
- end
- ).then((paginatedFiles) => {
- setFiles(paginatedFiles?.items.map(f => {
- return {
- key: f.id,
- begin: f.date,
- ...f
- }
- }))
-
- setPagination({
- total: paginatedFiles?.count,
- current: Math.floor(paginatedFiles?.skip / pageSize),
- })
-
- setTableUpdating(false)
- setShowLoader(false)
- }
- )
- } catch (ex) {
- notify(`Не удалось загрузить файлы по скважине "${idWell}"`, 'error')
- console.log(ex)
- }
- }
- GetDocuments()
- }, [idWell, range, page, selectedFileCategory, isTableUpdating])
-
- return (
-
-
-
Фильтр документов:
-
-
-
-
-
-
-
-
}
- onClick={openModal}
- >Загрузить файл
-
-
- {
- setIsModalVisible(false)
- setTableUpdating(true)
- }}>
-
-
-
-
-
setPage(page)
- }}
- rowKey={(record) => record.id}
- />
- );
-}
\ No newline at end of file
diff --git a/src/pages/Documents/DocumentsTemplate.jsx b/src/pages/Documents/DocumentsTemplate.jsx
new file mode 100644
index 0000000..793d29e
--- /dev/null
+++ b/src/pages/Documents/DocumentsTemplate.jsx
@@ -0,0 +1,111 @@
+import {useState, useEffect} from "react"
+import {Table, DatePicker, Button, ConfigProvider} from 'antd'
+import locale from "antd/lib/locale/ru_RU"
+import moment from 'moment'
+import { FileService } from '../../services/api'
+import { updateFromWebApiWrapperAsync, download, makePaginationObject} from '../../components/factory'
+import UploadFileForm from '../../components/UploadFileForm'
+import LoaderPortal from '../../components/LoaderPortal'
+
+const pageSize = 12
+const {RangePicker} = DatePicker;
+
+export default function DocumentsTemplate({idCategory, idWell}) {
+ const [page, setPage] = useState(1)
+ const [range, setRange] = useState([])
+ const [pagination, setPagination] = useState(null)
+ const [files, setFiles] = useState([])
+ const [showLoader, setShowLoader] = useState(false)
+
+ const uploadUrl = `/api/well/${idWell}/files/`
+
+ const handleFileNameCLick = async (_, row) => {
+ updateFromWebApiWrapperAsync(async ()=>{
+ await download(`/api/well/${idWell}/files/${row.id}`)
+ },
+ setShowLoader,
+ `Не удалось скачать файл ${row}`)
+ }
+
+ const columns = [
+ {
+ title: 'Документ',
+ key: 'document',
+ dataIndex: 'name',
+ render: (name, row) =>
+
+ },
+ {
+ title: 'Дата загрузки',
+ key: 'uploadDate',
+ dataIndex: 'uploadDate',
+ render: (item) => moment.utc(item).local().format('DD MMM YYYY, HH:mm:ss')
+ },
+ {
+ title: 'Ф.И.О.',
+ key: 'userName',
+ dataIndex: 'userName',
+ }
+ ];
+
+ const addKeysAndUpdateFiles = (items) =>{
+ const mappedFiles = items?.map(fileInfo => ({key: fileInfo.id, begin: fileInfo.date, ...fileInfo}))
+ setFiles(mappedFiles??[])
+ }
+
+ useEffect(() => {
+ let begin = null
+ let end = null
+ if (range?.length > 1) {
+ begin = range[0].toISOString()
+ end = range[1].toISOString()
+ }
+
+ updateFromWebApiWrapperAsync(
+ async ()=>{
+ const paginatedFiles = await FileService.getFilesInfo(
+ `${idWell}`,
+ (page - 1) * pageSize,
+ pageSize,
+ idCategory,
+ begin,
+ end)
+ if(!paginatedFiles)
+ return
+ addKeysAndUpdateFiles(paginatedFiles?.items)
+
+ const newPagination = makePaginationObject(paginatedFiles)
+ setPagination(newPagination)
+ },
+ setShowLoader,
+ `Не удалось загрузить файлы по скважине "${idWell}"`)
+ }, [idWell, range, page, idCategory])
+
+ return (
+
+ setShowLoader(true)}
+ onUploadComplete={()=>setShowLoader(false)}
+ />
+
+
Фильтр документов:
+
+
+
+
+ setPage(page)}}
+ rowKey={(record) => record.id}
+ />
+ );
+}
\ No newline at end of file
diff --git a/src/pages/Documents/index.jsx b/src/pages/Documents/index.jsx
new file mode 100644
index 0000000..aeff2f0
--- /dev/null
+++ b/src/pages/Documents/index.jsx
@@ -0,0 +1,27 @@
+import {Layout, Menu} from "antd";
+import {Switch, useParams} from "react-router-dom";
+import {makeMenuItems, makeRouteItems} from './menuItems'
+
+const { Content } = Layout
+
+export default function MenuDocuments({idWell}) {
+ let {category} = useParams()
+ const rootPath = `/well/${idWell}`
+
+ return(<>
+
+
+
+
+ {makeRouteItems('documentsPageMenu', `${rootPath}`, idWell)}
+
+
+
+ >)
+}
diff --git a/src/pages/Documents/menuItems.jsx b/src/pages/Documents/menuItems.jsx
new file mode 100644
index 0000000..ef8aa8d
--- /dev/null
+++ b/src/pages/Documents/menuItems.jsx
@@ -0,0 +1,58 @@
+import { Menu } from "antd";
+import { FolderOutlined } from "@ant-design/icons";
+import { Link, Route} from "react-router-dom";
+import DocumentsTemplate from './DocumentsTemplate'
+
+export const documentCategories = [
+ {id:1, key:'fluidService', title:'Растворный сервис'},
+ {id:2, key:'cementing', title:'Цементирование'},
+ {id:3, key:'nnb', title:'ННБ'},
+ {id:4, key:'gti', title:'ГТИ'},
+ {id:5, key:'documentsForWell', title:'Документы по скважине'},
+ {id:6, key:'supervisor', title:'Супервайзер'},
+ {id:7, key:'master', title:'Мастер'},
+]
+
+const makeMenuItem = (keyPrefix, keyValue, rootPath, title, other) => (
+
+ {title}
+ )
+
+const makeRouteItem = (keyPrefix, keyValue, rootPath, other) => (
+
+
+ )
+
+const formatRoutePath = (rootPath) =>{
+ let root = rootPath.endsWith('/')
+ ? rootPath.slice(0,-1)
+ : rootPath
+
+ root = root.endsWith('/document')
+ ? root
+ : `${root}/document`
+
+ return root
+}
+
+const getCategoriesByUserRole = (role) => documentCategories
+ .filter(cat => !cat.roles || cat.roles.includes('*') || cat.roles.includes(role))
+
+export const makeMenuItems = (keyPrefix, rootPath) => {
+ const root = formatRoutePath(rootPath)
+ const categories = getCategoriesByUserRole(localStorage['roleName'])
+ return categories.map(category =>
+ makeMenuItem(keyPrefix, category.key, root, category.title, {icon:}))
+}
+
+export const makeRouteItems = (keyPrefix, rootPath, idWell) => {
+ const root = formatRoutePath(rootPath)
+ const categories = getCategoriesByUserRole(localStorage['roleName'])
+ const routes = categories.map(category =>
+ makeRouteItem(keyPrefix, category.key, root, {idCategory: category.id, idWell: idWell}))
+ return routes;
+}
\ No newline at end of file
diff --git a/src/pages/FluidService.jsx b/src/pages/FluidService.jsx
deleted file mode 100644
index d75e422..0000000
--- a/src/pages/FluidService.jsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import Documents from "./Documents"
-
-export default function FluidService({selectedFileCategory}) {
-
- return(
-
- )
-}
\ No newline at end of file
diff --git a/src/pages/MenuDocuments.jsx b/src/pages/MenuDocuments.jsx
deleted file mode 100644
index 12380f3..0000000
--- a/src/pages/MenuDocuments.jsx
+++ /dev/null
@@ -1,87 +0,0 @@
-import { useState, useEffect } from "react";
-import {Layout, Menu} from "antd";
-import {FolderOutlined} from "@ant-design/icons";
-import {Link, Route, Switch, useLocation} from "react-router-dom";
-import Documents from "./Documents";
-import LastData from './LastData'
-
-const { Content } = Layout
-
-export default function MenuDocuments({idWell}) {
- let currentPath = useLocation().pathname
-
- const rootPath = `/well/${idWell}`
-
- const [selectedElement, setSelectedElement] = useState('fluidService')
-
- useEffect(() => {
- let pathLastElement = currentPath.split('/').pop()
- setSelectedElement(pathLastElement)
- }, [currentPath])
-
- return(
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >)
-}
diff --git a/src/pages/Smbo/EquipmentDetails.jsx b/src/pages/Smbo/EquipmentDetails.jsx
index 15421a3..5178236 100644
--- a/src/pages/Smbo/EquipmentDetails.jsx
+++ b/src/pages/Smbo/EquipmentDetails.jsx
@@ -1,5 +1,5 @@
import {Row, Col} from 'antd'
-import Documents from '../Documents'
+import Documents from '../Documents/DocumentsTemplate'
import '../../styles/equipment_details.css'
export default function EquipmentDetails({id, equipmentTimers, equipmentSensors}) {
diff --git a/src/pages/TelemetryView/CustomColumn.jsx b/src/pages/TelemetryView/CustomColumn.jsx
index 0b49bd2..ed90fce 100644
--- a/src/pages/TelemetryView/CustomColumn.jsx
+++ b/src/pages/TelemetryView/CustomColumn.jsx
@@ -1,5 +1,5 @@
import {Display} from '../../components/Display'
-import RigMnemo from '../../components/RigMnemo'
+import RigMnemo from './RigMnemo'
const params = [
{label:'Рот., об/мин', accessorName:'rotorSpeed', isArrowVisible:true},
diff --git a/src/components/RigMnemo.jsx b/src/pages/TelemetryView/RigMnemo.jsx
similarity index 100%
rename from src/components/RigMnemo.jsx
rename to src/pages/TelemetryView/RigMnemo.jsx
diff --git a/src/pages/Well.jsx b/src/pages/Well.jsx
index d74f0be..650fabd 100644
--- a/src/pages/Well.jsx
+++ b/src/pages/Well.jsx
@@ -1,124 +1,116 @@
-import {Layout, Menu} from "antd";
-import {FolderOutlined, FundViewOutlined} from "@ant-design/icons";
-import {Link, Redirect, Route, Switch, useParams} from "react-router-dom";
+import { Layout, Menu } from "antd";
+import { FolderOutlined, FundViewOutlined } from "@ant-design/icons";
+import { Link, Redirect, Route, Switch, useParams } from "react-router-dom";
import TelemetryView from "./TelemetryView";
import Messages from "../pages/Messages";
import Report from "../pages/Report";
import Archive from "../pages/Archive";
import Analysis from "../pages/Analysis";
import WellAnalysis from "../pages/WellAnalysis";
-import MenuDocuments from "./MenuDocuments";
-import WellStat from "./WellStat"
-import Smbo from "./Smbo"
+import Documents from "../pages/Documents";
+import LastData from '../pages/LastData'
+import { makeMenuItems } from "./Documents/menuItems";
+import WellStat from "./WellStat";
+import Smbo from "./Smbo";
-const { Content } = Layout
+const { Content } = Layout;
export default function Well() {
- let { idWell } = useParams()
- const rootPath = `/well/${idWell}`
+ let { idWell } = useParams();
+ const rootPath = `/well/${idWell}`;
- const {SubMenu} = Menu
+ const { SubMenu } = Menu;
- return (<>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- >)
+ >
+ );
}