first commit
|
|
@ -0,0 +1,2 @@
|
||||||
|
GENERATE_SOURCEMAP=true
|
||||||
|
PUBLIC_URL=/ssDp
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
GENERATE_SOURCEMAP=false
|
||||||
|
PUBLIC_URL=/ssDp
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.js
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
build.zip
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
yarn.lock
|
||||||
|
build.7z
|
||||||
|
|
||||||
|
#ai
|
||||||
|
.serena/
|
||||||
|
CLAUDE.md
|
||||||
|
local-ai/
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
const CracoLessPlugin = require('craco-less');
|
||||||
|
const pxToViewport = require('postcss-px-to-viewport-8-plugin');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
style: {
|
||||||
|
postcss: {
|
||||||
|
mode: 'extends',
|
||||||
|
loaderOptions: {
|
||||||
|
postcssOptions: {
|
||||||
|
ident: 'postcss',
|
||||||
|
plugins: [
|
||||||
|
pxToViewport({
|
||||||
|
viewportWidth: 1920, // 设计稿宽度
|
||||||
|
unitPrecision: 5, // 单位转换后保留的精度
|
||||||
|
viewportUnit: 'vw', // 希望使用的视口单位
|
||||||
|
selectorBlackList: [], // 需要忽略的CSS选择器
|
||||||
|
minPixelValue: 1, // 小于或等于`1px`不转换为视口单位
|
||||||
|
mediaQuery: false, // 允许在媒体查询中转换`px`
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
plugin: CracoLessPlugin,
|
||||||
|
options: {
|
||||||
|
lessLoaderOptions: {
|
||||||
|
lessOptions: {
|
||||||
|
modifyVars: {
|
||||||
|
'@primary-color': '#1890FF',
|
||||||
|
'@primary-color-hover': '#3B7CFF',
|
||||||
|
'@error-color': '#F55E55',
|
||||||
|
'@text-color': '#3B4859',
|
||||||
|
'@menu-dark-bg': '#0052D9',
|
||||||
|
'@layout-body-background': '#eeeeee',
|
||||||
|
'@height-base': '36px',
|
||||||
|
'@form-vertical-label-padding': '0 0 10px',
|
||||||
|
'@normal-color': '#EFF1F5',
|
||||||
|
'@label-color': '#3B4859',
|
||||||
|
'@card-background': '#fbfbfb',
|
||||||
|
'@heading-color': '#3B4859',
|
||||||
|
},
|
||||||
|
javascriptEnabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
{
|
||||||
|
"name": "wswl-web",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@ant-design/charts": "^1.4.2",
|
||||||
|
"@ant-design/graphs": "^1.4.0",
|
||||||
|
"@ant-design/icons": "^5.3.6",
|
||||||
|
"@ant-design/pro-form": "^1.49.6",
|
||||||
|
"@craco/craco": "^7.0.0",
|
||||||
|
"@rematch/core": "^2.2.0",
|
||||||
|
"@turf/turf": "^6.5.0",
|
||||||
|
"@types/crypto-js": "^4.1.1",
|
||||||
|
"@types/geojson": "^7946.0.8",
|
||||||
|
"@types/leaflet": "^1.7.11",
|
||||||
|
"@types/node": "^16.11.45",
|
||||||
|
"@types/react": "^18.0.15",
|
||||||
|
"@types/react-dom": "^18.0.6",
|
||||||
|
"@wangeditor/editor": "^5.1.23",
|
||||||
|
"@wangeditor/editor-for-react": "^1.0.6",
|
||||||
|
"antd": "^4.21.7",
|
||||||
|
"clone": "^2.1.2",
|
||||||
|
"clsx": "^1.2.1",
|
||||||
|
"copy-to-clipboard": "^3.3.3",
|
||||||
|
"craco-less": "2.1.0-alpha.0",
|
||||||
|
"crypto-js": "^4.1.1",
|
||||||
|
"echarts": "^4.9.0",
|
||||||
|
"echarts-for-react": "^3.0.2",
|
||||||
|
"http-proxy-middleware": "^2.0.6",
|
||||||
|
"moment": "^2.29.4",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-audio-player": "^0.17.0",
|
||||||
|
"react-cookies": "^0.1.1",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"react-redux": "^8.0.2",
|
||||||
|
"react-router": "^6.3.0",
|
||||||
|
"react-router-dom": "^6.3.0",
|
||||||
|
"react-scripts": "5.0.1",
|
||||||
|
"redux": "^4.2.0",
|
||||||
|
"typescript": "^4.7.4"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "craco start",
|
||||||
|
"build": "craco build"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"extends": [
|
||||||
|
"react-app"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"browserslist": {
|
||||||
|
"production": [
|
||||||
|
">0.2%",
|
||||||
|
"not dead",
|
||||||
|
"not op_mini all"
|
||||||
|
],
|
||||||
|
"development": [
|
||||||
|
"last 1 chrome version",
|
||||||
|
"last 1 firefox version",
|
||||||
|
"last 1 safari version"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"postcss-px-to-viewport-8-plugin": "^1.2.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 567 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 619 B |
|
After Width: | Height: | Size: 589 B |
|
After Width: | Height: | Size: 4.2 KiB |
|
|
@ -0,0 +1,59 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<meta name="theme-color" content="#000000" />
|
||||||
|
<meta name="description" content="标题" />
|
||||||
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||||
|
<!--
|
||||||
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
|
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||||
|
-->
|
||||||
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
|
<!--
|
||||||
|
Notice the use of %PUBLIC_URL% in the tags above.
|
||||||
|
It will be replaced with the URL of the `public` folder during the build.
|
||||||
|
Only files inside the `public` folder can be referenced from the HTML.
|
||||||
|
|
||||||
|
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||||
|
work correctly both with client-side routing and a non-root public URL.
|
||||||
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
|
-->
|
||||||
|
<title>双石水库矩阵化管理</title>
|
||||||
|
<!-- <script src="%PUBLIC_URL%/iframe/socket.io.js"></script> -->
|
||||||
|
<style>
|
||||||
|
.lf {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rf {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clearFloat:after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
<div id="root"></div>
|
||||||
|
<!--
|
||||||
|
This HTML file is a template.
|
||||||
|
If you open it directly in the browser, you will see an empty page.
|
||||||
|
|
||||||
|
You can add webfonts, meta tags, or analytics to this file.
|
||||||
|
The build step will place the bundled scripts into the <body> tag.
|
||||||
|
|
||||||
|
To begin the development, run `npm start` or `yarn start`.
|
||||||
|
To create a production bundle, use `npm run build` or `yarn build`.
|
||||||
|
-->
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
After Width: | Height: | Size: 567 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 619 B |
|
After Width: | Height: | Size: 589 B |
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { Select } from "antd"
|
||||||
|
|
||||||
|
|
||||||
|
const NormalSelect = function (prop) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Select {...prop}
|
||||||
|
getPopupContainer={triggerNode => triggerNode.parentNode || document.body}
|
||||||
|
style={prop.style||{width:'100%'}}
|
||||||
|
showSearch
|
||||||
|
allowClear={prop.allowClear===false?false:true}
|
||||||
|
optionFilterProp="children"
|
||||||
|
filterOption={(input, option) =>
|
||||||
|
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NormalSelect
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
.ant-table-thead>tr>th {
|
||||||
|
border-bottom: none !important;
|
||||||
|
padding: 6px 6px;
|
||||||
|
background: #ECF2F9 !important;
|
||||||
|
color: #333 !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
width: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*&:first-child {
|
||||||
|
border-top-left-radius: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-top-right-radius: 16px !important;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-table {
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-table-tbody>tr>td {
|
||||||
|
//border-bottom: none !important;
|
||||||
|
background: #fff;
|
||||||
|
//box-shadow: 3px 2px 3px 2px #E8ECF1;
|
||||||
|
padding: 6px 6px;
|
||||||
|
|
||||||
|
/* &:first-child {
|
||||||
|
border-top-left-radius: 8px;
|
||||||
|
border-bottom-left-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-top-right-radius: 8px;
|
||||||
|
border-bottom-right-radius: 8px;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-table table,.ant-table.ant-table-bordered > .ant-table-container,
|
||||||
|
.ant-table.ant-table-bordered > .ant-table-container > .ant-table-content > table > tbody > tr > td{
|
||||||
|
//border-spacing: 0 8px !important;
|
||||||
|
//border:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.ant-radio-group {
|
||||||
|
.ant-radio-button-wrapper:first-child {
|
||||||
|
// border-radius: 8px 0 0 8px !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-radio-button-wrapper:last-child {
|
||||||
|
// border-radius: 0 8px 8px 0 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-radio-button-wrapper {
|
||||||
|
border: 1px solid @primary-color !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #D9EBFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-radio-button-wrapper {
|
||||||
|
color: #3B7CFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-checkbox-checked {
|
||||||
|
.ant-checkbox-inner {
|
||||||
|
background-color: #3b7cff !important;
|
||||||
|
border-color: #3b7cff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-checkbox-inner {
|
||||||
|
border-radius: 4px !important;
|
||||||
|
border-width: 1.4px !important;
|
||||||
|
border-color: #C7CBD3 !important;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Modal, message } from 'antd';
|
||||||
|
import { createCrudService } from './_';
|
||||||
|
import apiurl from '../../service/apiurl';
|
||||||
|
|
||||||
|
class BasicCrudModal extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
record: null,
|
||||||
|
open: false,
|
||||||
|
mode: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
showEdit(record) {
|
||||||
|
record = record || {};
|
||||||
|
this.setState({ record, open: true, mode: 'edit' });
|
||||||
|
}
|
||||||
|
showSave(record) {
|
||||||
|
record = record || {};
|
||||||
|
this.setState({ record, open: true, mode: 'save' });
|
||||||
|
}
|
||||||
|
showView(record) {
|
||||||
|
record = record || {};
|
||||||
|
this.setState({ record, open: true, mode: 'view' });
|
||||||
|
}
|
||||||
|
onEdit = (path, values) => {
|
||||||
|
createCrudService(path).edit(values).then((result) => {
|
||||||
|
if (result?.code === 200) {
|
||||||
|
message.success('修改成功');
|
||||||
|
this.setState({ open: false });
|
||||||
|
|
||||||
|
if (this.props.onCrudSuccess) {
|
||||||
|
this.props.onCrudSuccess();
|
||||||
|
}
|
||||||
|
} else if (result?.code === 400) {
|
||||||
|
message.error(result?.description);
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
message.error(result?.msg||'修改失败');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onSave = (path,values) => {
|
||||||
|
createCrudService(path).save(values).then((result) => {
|
||||||
|
if (result?.code === 200) {
|
||||||
|
message.success('保存成功');
|
||||||
|
this.setState({ open: false });
|
||||||
|
if (this.props.onCrudSuccess) {
|
||||||
|
this.props.onCrudSuccess();
|
||||||
|
}
|
||||||
|
} else if (result?.code === 400) {
|
||||||
|
message.error(result?.description||'修改失败');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
message.error(result?.msg||'保存失败');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onDelete = (path, values) => {
|
||||||
|
createCrudService(path).del(values).then((result) => {
|
||||||
|
if (result?.code === 200) {
|
||||||
|
message.success('删除成功');
|
||||||
|
this.setState({ open: false });
|
||||||
|
if (this.props.onCrudSuccess) {
|
||||||
|
this.props.onCrudSuccess();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.error(result?.msg||'删除失败');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeleteGet = (path,values) => {
|
||||||
|
createCrudService(path).delGet(values).then((result) => {
|
||||||
|
if (result?.code === 200) {
|
||||||
|
message.success('删除成功');
|
||||||
|
this.setState({ open: false });
|
||||||
|
if (this.props.onCrudSuccess) {
|
||||||
|
this.props.onCrudSuccess();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.error(result?.msg||'删除失败');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
whichMod = (value) => {
|
||||||
|
if(value === 'save'){
|
||||||
|
return '新增'
|
||||||
|
}else if (value === 'add' || value === ''){
|
||||||
|
return '新增'
|
||||||
|
}else if (value === 'edit'){
|
||||||
|
return '修改'
|
||||||
|
}else if (value === 'view'){
|
||||||
|
return '查看'
|
||||||
|
}else if (value === 'show' || value === 'review'){
|
||||||
|
return ''
|
||||||
|
}else if (value === 'zg'){
|
||||||
|
return '整改详情'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return '新增'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { record, open, mode } = this.state;
|
||||||
|
const { width, title, style, wrapClassName, formProps, component: Component,title1 } = this.props;
|
||||||
|
if (!record || !open) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
width={width || 600}
|
||||||
|
style={style || { top: 10 }}
|
||||||
|
wrapClassName={wrapClassName}
|
||||||
|
open={true}
|
||||||
|
title={title1 ||`${this.whichMod(mode)}${title}`}
|
||||||
|
footer={null}
|
||||||
|
destroyOnClose
|
||||||
|
onCancel={() => { this.setState({ open: false }) }}
|
||||||
|
>
|
||||||
|
<Component
|
||||||
|
mode={mode}
|
||||||
|
close={()=>{this.setState({ open: false })}}
|
||||||
|
onCrudSuccess={this.props.onCrudSuccess}
|
||||||
|
record={record}
|
||||||
|
onEdit={this.onEdit}
|
||||||
|
onSave={this.onSave}
|
||||||
|
formProps={formProps}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BasicCrudModal;
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Button, Popconfirm } from 'antd';
|
||||||
|
import { EditOutlined, DeleteOutlined, UndoOutlined,PlusCircleOutlined, FileSearchOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
|
export function CrudOpRender_icon({ command, edit, del, restore, add, view }) {
|
||||||
|
return (
|
||||||
|
<div style={{ display: 'inline' }}>
|
||||||
|
{
|
||||||
|
add ? (
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" icon={<PlusCircleOutlined />} onClick={command('add')} title="增加"></Button>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
edit ? (
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" icon={<EditOutlined />} onClick={command('edit')} title="编辑"></Button>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
view ? (
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" icon={<FileSearchOutlined />} onClick={command('view')} title="查看"></Button>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
restore ? (
|
||||||
|
<Popconfirm title="确定要恢复吗?" onConfirm={command('restore')}>
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" icon={<UndoOutlined />} title="恢复"></Button>
|
||||||
|
</Popconfirm>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
del ? (
|
||||||
|
<Popconfirm title="确定要删除吗?" onConfirm={command('del')}>
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" icon={<DeleteOutlined />} size="small" title='删除'></Button>
|
||||||
|
</Popconfirm>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CrudOpRender_text({ command,picReview, edit,detail, dispatch,del, restore, add,similarAdd, view,zg, cjxgl,review,download,record }) {
|
||||||
|
return (
|
||||||
|
<div style={{ display: 'inline' }}>
|
||||||
|
{
|
||||||
|
record ? (
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" onClick={command('record')} title="培训记录">培训记录</Button>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
add ? (
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" onClick={command('add')} title="增加">增加</Button>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
detail ? (
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" onClick={command('view')} title="详情">详情</Button>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
similarAdd ? (
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" onClick={command('similarAdd')} title="复制">复制</Button>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
edit ? (
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" onClick={command('edit')} title="编辑">编辑</Button>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
view ? (
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" onClick={command('view')} title="查看">查看</Button>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
cjxgl ? (
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" onClick={command('cjxgl')} title="采集项管理">采集项管理</Button>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
review ? (
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" onClick={command('review')} title="预览">预览</Button>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
picReview ? (
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" onClick={command('picReview')} title="预览">预览</Button>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
zg ? (
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" onClick={command('edit')} title="整改">整改</Button>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
download ? (
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" onClick={command('download')} title="下载">下载</Button>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
restore ? (
|
||||||
|
<Popconfirm title="确定要恢复吗?" onConfirm={command('restore')}>
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" title="恢复">恢复</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
dispatch ? (
|
||||||
|
<Popconfirm title="确定要下发吗?" onConfirm={command('dispatch')}>
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" title="下发">下发</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
del ? (
|
||||||
|
<Popconfirm title="确定要删除吗?" onConfirm={command('del')}>
|
||||||
|
<Button style={{ marginRight: 4,color:'red' }} type="link" size="small" title='删除'>删除</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function CrudOpRender_YJPZ({ command, edit, del, restore, add, view }) {
|
||||||
|
return (
|
||||||
|
<div style={{ display: 'inline' }}>
|
||||||
|
{
|
||||||
|
edit ? (
|
||||||
|
<Button style={{ marginRight: 4 }} type="link" size="small" onClick={command('edit')} title="预警配置">预警配置</Button>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
export const DEF_INPUT_LEN = 464;
|
||||||
|
export const DEF_INPUT_LEN_QUARTS = 92;
|
||||||
|
|
||||||
|
export const DEF_LAYOUT = {
|
||||||
|
labelCol: { span: 8 },
|
||||||
|
wrapperCol: { span: 16 },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DEF_TAIL_LAYOUT = {
|
||||||
|
wrapperCol: { offset: 8, span: 16 },
|
||||||
|
};
|
||||||
|
|
||||||
|
//复制过来
|
||||||
|
export const formItemLayout = {
|
||||||
|
labelCol: { span: 6 },
|
||||||
|
wrapperCol: { span: 14 },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tailItemLayout = {
|
||||||
|
wrapperCol: { span: 17, offset: 7 },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const formItemLayoutTight = {
|
||||||
|
labelCol: { span: 3 },
|
||||||
|
wrapperCol: { span: 19 },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tailItemLayoutTight = {
|
||||||
|
wrapperCol: { span: 20, offset: 4 },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const itemLayoutPercent = {
|
||||||
|
labelCol: { span: 0 },
|
||||||
|
wrapperCol: { span: 24 },
|
||||||
|
};
|
||||||
|
export const btnItemLayout = {
|
||||||
|
wrapperCol: { span: 4, offset: 20 },
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
import {httppost, httpPostFile, httpget } from "../../utils/request";
|
||||||
|
|
||||||
|
export async function paginate(url, params = {}) {
|
||||||
|
const {pageNumber, pageSize, ...ret} = params;
|
||||||
|
const pam = {
|
||||||
|
pageSo: {
|
||||||
|
pageSize,
|
||||||
|
pageNumber
|
||||||
|
},
|
||||||
|
...ret
|
||||||
|
}
|
||||||
|
const result = await httppost(url, pam);
|
||||||
|
if (result && result.data) {
|
||||||
|
const {data} = result;
|
||||||
|
return {
|
||||||
|
list: data.records.map((m, index) => ({inx: (pageNumber - 1) * pageSize + index + 1, ...m})),
|
||||||
|
totalRow: data.total
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {list: [], totalRow: 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function createCrudService(urlSet) {
|
||||||
|
const find = async (params) => {
|
||||||
|
return paginate(urlSet, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
const save = async (params) => {
|
||||||
|
const resData = await httppost(urlSet, params) || {};
|
||||||
|
return resData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const edit = async (params) => {
|
||||||
|
const resData = await httppost(urlSet, params) || {};
|
||||||
|
return resData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const del = async (params) => {
|
||||||
|
const resData = await httppost(urlSet, params) || {};
|
||||||
|
return resData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const delGet = async (params) => {
|
||||||
|
const resData = await httpget(urlSet, params) || {};
|
||||||
|
return resData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const list = async (params) => {
|
||||||
|
const {pageNumber, pageSize, sort, search} = params;
|
||||||
|
const {data} = await httppost(urlSet, params) || {};
|
||||||
|
if (data) {
|
||||||
|
return {
|
||||||
|
list: data.map((m, index) => ({inx: (pageNumber - 1) * pageSize + index + 1, ...m})),
|
||||||
|
totalRow: data?.length
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {list: data, totalRow: data?.length};
|
||||||
|
}
|
||||||
|
|
||||||
|
const downLoad = async (params) => {
|
||||||
|
fetch(urlSet, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(params),
|
||||||
|
// responseType : 'blob',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
}).then(function (response) {
|
||||||
|
console.log('response', response)
|
||||||
|
|
||||||
|
return response.blob();
|
||||||
|
}).then(function (blob) {
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.style.display = 'none'
|
||||||
|
// link.download = '到处文件'
|
||||||
|
link.href = URL.createObjectURL(blob)
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
// 释放的 URL 对象以及移除 a 标签
|
||||||
|
URL.revokeObjectURL(link.href)
|
||||||
|
document.body.removeChild(link)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const upLoad = async (params) => {
|
||||||
|
const {data} = await httpPostFile(urlSet, params) || {};
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
find: find,
|
||||||
|
list: list,
|
||||||
|
save: save,
|
||||||
|
edit: edit,
|
||||||
|
del: del,
|
||||||
|
upLoad: upLoad,
|
||||||
|
downLoad: downLoad,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
import { useState, useRef, useEffect } from 'react';
|
||||||
|
import { ListProps, TableProps } from 'antd';
|
||||||
|
import { PageResult, SearchOption } from '../../service/def';
|
||||||
|
import { camel2UnderLine } from "../../utils/utils";
|
||||||
|
|
||||||
|
export type PageTableContext<T> = {
|
||||||
|
tableProps: TableProps<T>,
|
||||||
|
listProps?: ListProps<T>,
|
||||||
|
search: (params?: SearchOption) => void,
|
||||||
|
refresh: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
//最基础版本的pageTable
|
||||||
|
function usePageTable<T>(
|
||||||
|
service: (params?: SearchOption) => Promise<PageResult<T>>,
|
||||||
|
options: SearchOption = {}
|
||||||
|
): PageTableContext<T> {
|
||||||
|
const [ state, setState ] = useState(()=>({
|
||||||
|
data: [],
|
||||||
|
total: 0,
|
||||||
|
loading: false,
|
||||||
|
pageSize: options.pageSize ?? 10,
|
||||||
|
pageNumber: options.pageNumber ?? 1,
|
||||||
|
sortField: options.sortField,
|
||||||
|
sortOrder: options.sortOrder,
|
||||||
|
search: options.search || {},
|
||||||
|
}))
|
||||||
|
|
||||||
|
const search = async(opt: SearchOption = {})=>{
|
||||||
|
setState(s => ({ ...s, loading: true }));
|
||||||
|
const pageParams = {
|
||||||
|
pageNumber: opt?.pageNumber ?? state.pageNumber,
|
||||||
|
pageSize: opt?.pageSize ?? state.pageSize,
|
||||||
|
sortField: opt?.sortField ?? state.sortField,
|
||||||
|
sortOrder: opt?.sortOrder ?? state.sortOrder,
|
||||||
|
search: opt?.search ?? state.search,
|
||||||
|
};
|
||||||
|
const { search, ...params } = pageParams;
|
||||||
|
const data:any = await service({ ...search, ...params })
|
||||||
|
////给每个数据加一个key
|
||||||
|
data.list.forEach((item:any,index:number) => {
|
||||||
|
item.dataIndex = new Date().getTime()+'_'+index
|
||||||
|
});
|
||||||
|
|
||||||
|
setState({
|
||||||
|
...pageParams,
|
||||||
|
data: data.list,
|
||||||
|
total: data.totalRow,
|
||||||
|
loading: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleTableChange = (pagination: any, filters: any, sort: any) => {
|
||||||
|
const { field, order } = sort;
|
||||||
|
if (field && order) {
|
||||||
|
const sortOrder = order === 'ascend' ? 'asc' : 'desc';
|
||||||
|
const _field = camel2UnderLine(field);
|
||||||
|
search({ pageNumber: pagination.current, pageSize: state.pageSize, sortOrder, sortField: _field });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
search({ pageNumber: pagination.current, pageSize: pagination.pageSize });
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
tableProps: {
|
||||||
|
size: 'small',
|
||||||
|
bordered: true,
|
||||||
|
dataSource: state.data,
|
||||||
|
pagination: {
|
||||||
|
showTotal: (totalRow) => `共${totalRow}条`,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showQuickJumper: true,
|
||||||
|
pageSize: state.pageSize,
|
||||||
|
current: state.pageNumber,
|
||||||
|
total: state.total,
|
||||||
|
pageSizeOptions: ['10', '15', '20', '50', '100'],
|
||||||
|
hideOnSinglePage: true,
|
||||||
|
},
|
||||||
|
loading: state.loading,
|
||||||
|
onChange: handleTableChange,
|
||||||
|
},
|
||||||
|
search: (params) => search({ ...params, pageNumber: 1 }),
|
||||||
|
refresh: search,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default usePageTable
|
||||||
|
|
@ -0,0 +1,191 @@
|
||||||
|
@import '~antd/dist/antd.less';
|
||||||
|
|
||||||
|
html{
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||||
|
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||||
|
sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||||
|
monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#root {
|
||||||
|
min-width: 1280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-grow-1 {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 4px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: #eee;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: #ECF2F9;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #ECF2F9;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.ant-card-body{//此处不加.ant-card-body为导致首页的滚动条样式受到影响
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 8px !important;
|
||||||
|
height: 8px !important;
|
||||||
|
// background: rgba(250, 15, 15, ) !important;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-corner {
|
||||||
|
//background-color: gray!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-table-content::-webkit-scrollbar-thumb,.ant-table-body::-webkit-scrollbar-thumb {
|
||||||
|
background: #C1C1C1;//#ECF2F9;
|
||||||
|
}
|
||||||
|
.ant-table-content::-webkit-scrollbar-thumb,.ant-table-body::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #C1C1C1;//#ECF2F9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-modal-title{
|
||||||
|
font-size:16px;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.adcdTreeSelectorBox{
|
||||||
|
width: 230px;
|
||||||
|
height:calc( 100vh - 145px );
|
||||||
|
margin:0 20px 0 0;
|
||||||
|
background: #fff;
|
||||||
|
//box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
position:relative;
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.treeBox{
|
||||||
|
//height:calc( 100vh - 158px );
|
||||||
|
overflow: hidden auto;
|
||||||
|
padding: 8px 0 0 2px;
|
||||||
|
border-top: 1px solid #d9d9d9;
|
||||||
|
}
|
||||||
|
.ant-input-group .ant-input,.ant-btn{
|
||||||
|
border:0;
|
||||||
|
}
|
||||||
|
.ant-input-affix-wrapper{
|
||||||
|
border:0;
|
||||||
|
//border-right: 2px solid #d9d9d9;
|
||||||
|
}
|
||||||
|
.checkboxBox{
|
||||||
|
position:absolute;
|
||||||
|
top:34px;
|
||||||
|
width:100%;
|
||||||
|
height:30px;
|
||||||
|
background:#fff;
|
||||||
|
border-top: 1px solid #d9d9d9;
|
||||||
|
padding-top:4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.adcdTreeTableBox{
|
||||||
|
width:calc( 100vw - 602px );
|
||||||
|
height:calc( 100vh - 143px );
|
||||||
|
background: #fff;
|
||||||
|
//box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.CrudAdcdTreeTableBox{
|
||||||
|
width:calc( 100vw - 602px );
|
||||||
|
height:calc( 100vh - 143px );
|
||||||
|
background: #fff;
|
||||||
|
//box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.radarVideoModal{
|
||||||
|
.ant-modal-content{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
.ant-modal-body{
|
||||||
|
width: 100%;
|
||||||
|
height: calc( 100% - 120px );
|
||||||
|
padding: 0 30px;
|
||||||
|
}
|
||||||
|
.ant-tabs-tabpane{
|
||||||
|
height: calc( 76vh - 120px );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbarBox{
|
||||||
|
.ant-form-item{
|
||||||
|
padding: 5px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.flexwarp{
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.flexcc{
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.flexsbc{
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.flexsac{
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.flexac{
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.flexfc{
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-table-tbody{
|
||||||
|
.ant-table-measure-row{
|
||||||
|
td{
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// tr:nth-child(odd) {
|
||||||
|
// td{
|
||||||
|
// background-color: #f5f8fe !important;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
.pageBox{
|
||||||
|
height:calc( 100vh - 90px );
|
||||||
|
overflow-y: scroll;
|
||||||
|
background-color: #fff !important;
|
||||||
|
padding:0;
|
||||||
|
margin:0 0 0 5px;
|
||||||
|
.ant-table-container{
|
||||||
|
border-left:1px solid #d9d9d9 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.formItemHidden{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom/client';
|
||||||
|
import { ConfigProvider } from 'antd';
|
||||||
|
import zhCN from 'antd/lib/locale/zh_CN';
|
||||||
|
import 'moment/locale/zh-cn';
|
||||||
|
import { Provider } from 'react-redux';
|
||||||
|
import { HashRouter } from 'react-router-dom';
|
||||||
|
import { store } from './models/store';
|
||||||
|
import AppRouters from './views/AppRouters';
|
||||||
|
import './index.less';
|
||||||
|
import './components/ant_override.less'
|
||||||
|
|
||||||
|
const root = ReactDOM.createRoot(
|
||||||
|
document.getElementById('root') as HTMLElement
|
||||||
|
);
|
||||||
|
|
||||||
|
root.render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<HashRouter>
|
||||||
|
<ConfigProvider locale={zhCN}>
|
||||||
|
<AppRouters />
|
||||||
|
</ConfigProvider>
|
||||||
|
</HashRouter>
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
|
@ -0,0 +1,336 @@
|
||||||
|
import { Position } from "geojson";
|
||||||
|
|
||||||
|
|
||||||
|
export type PageResult<T> = {
|
||||||
|
list: T[];
|
||||||
|
totalRow: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type SearchOption = {
|
||||||
|
pageSize?: number;
|
||||||
|
pageNumber?: number;
|
||||||
|
search?: { [key: string]: any };
|
||||||
|
sortField?: string;
|
||||||
|
sortOrder?: 'asc' | 'desc';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type MenuItem = {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
path?: string;
|
||||||
|
redirect?: string;
|
||||||
|
icon?: string;
|
||||||
|
children?: MenuItem[];
|
||||||
|
isRead?:any
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type CCTVObject = {
|
||||||
|
id: number;
|
||||||
|
indexCode: string;
|
||||||
|
stcd: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SZObject = {
|
||||||
|
gateCode: string; // 水闸工程代码 string
|
||||||
|
gateName: string; // 水闸名称 string
|
||||||
|
cctvs: CCTVObject[]; // 视频点列表 array object
|
||||||
|
ctrlType: 0 | 1; // 是否可控 0 否 1 是 integer
|
||||||
|
gaorNum: number; //闸孔数量 number
|
||||||
|
lgtd: number; // 经度 number
|
||||||
|
lttd: number; // 纬度 number
|
||||||
|
|
||||||
|
|
||||||
|
chanName?: string; // 所在渠道 string
|
||||||
|
adNamee?: string; // 所属行政位置 string
|
||||||
|
admDep?: string; // 归口管理部门:1水利部门,2电力部门,3农业部门,4 林业部门,5城建部门,6航运部门,7环保部门,9其他部门 string
|
||||||
|
bnch?: string; // 桩号 string
|
||||||
|
collDate?: any; // 属性采集时间 object
|
||||||
|
compDate?: string; // 建成时间 string
|
||||||
|
desTotInsCap?: string; // 设计装机总容量(MW) string
|
||||||
|
dsfl?: number; // 设计流量(m³/s) number
|
||||||
|
endLat?: number; // 终点纬度 number
|
||||||
|
endLong?: number; // 终点经度 number
|
||||||
|
engGrad?: string; // 工程等别:1Ⅰ,2Ⅱ,3Ⅲ,4Ⅳ,5Ⅴ string
|
||||||
|
engManName?: string; // 管理单位 string
|
||||||
|
engStat?: string; // 工程建设情况:0未建,1在建,2已建 string
|
||||||
|
gateSize?: string; // 闸门尺寸(m) string
|
||||||
|
gateTp?: string; // 闸门类型 string
|
||||||
|
hdgrTp?: string; // 启闭设备类型:1卷扬式,2螺杆式,3凹轮式,4涡轮式,5丝杆式 string
|
||||||
|
inEle?: number; // 进口高程(m) number
|
||||||
|
insPow?: number; // 装机功率(KW) number
|
||||||
|
lockDisc?: number; // 最大过闸流量(m³/s) number
|
||||||
|
note?: string; // 备注 string
|
||||||
|
outEle?: number; // 出口高程(m) number
|
||||||
|
pwrTp?: string; // 动力类型:1手动,2电动,3手电两用 string
|
||||||
|
runStat?: string; // 运行情况:1在用良好,2在用故障,3停用 string
|
||||||
|
startDate?: any; // 开工时间 object
|
||||||
|
startLat?: number; // 起点纬度 number
|
||||||
|
startLong?: number; // 起点经度 number
|
||||||
|
stfl?: number; // 实达流量(m³/s) number
|
||||||
|
updDate?: any; // 属性更新时间 object
|
||||||
|
updserDate?: string; // 更新或维修时间 string
|
||||||
|
updserInvst?: number; // 更新或维修投资 number
|
||||||
|
updserRsn?: string; // 更新或维修原因 string
|
||||||
|
wagaType?: string; // 水闸类别:1分(泄)洪闸,2节制闸,3排(退)水闸,4引(进)水闸,5 挡潮闸,6 船闸,9其他 string
|
||||||
|
wagaUse?: string; // 水闸用途 string
|
||||||
|
wainWasoType?: string; // 取水水源类型:1水库,2湖泊,3河流,4其他 string
|
||||||
|
|
||||||
|
_z1: number;
|
||||||
|
_z2: number;
|
||||||
|
_kd: number;
|
||||||
|
_ll: number;
|
||||||
|
_tm: string;
|
||||||
|
_status: 0 | 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type ZMInfo = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
kdMax: number; // 也许有同一个闸的不同闸门的开度不一样?
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ZMRuntime = {
|
||||||
|
id: string; // eqpno
|
||||||
|
|
||||||
|
gtophgt?: number;
|
||||||
|
gtq?: number;
|
||||||
|
maxhgt?: number;
|
||||||
|
boot?: boolean;
|
||||||
|
shut?: boolean;
|
||||||
|
signal?: boolean;
|
||||||
|
power?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type ZmSocketPack = {
|
||||||
|
stcd: string,
|
||||||
|
eqpno: string,
|
||||||
|
tm: string;
|
||||||
|
|
||||||
|
gtophgt?: number;
|
||||||
|
gtq?: number;
|
||||||
|
maxhgt?: number;
|
||||||
|
boot?: boolean;
|
||||||
|
shut?: boolean;
|
||||||
|
signal?: boolean;
|
||||||
|
power?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type demoZmInfo = {
|
||||||
|
stcd: string;
|
||||||
|
stnm: string;
|
||||||
|
qqnm: string;
|
||||||
|
type: string;
|
||||||
|
status: '在线' | '离线';
|
||||||
|
time: string;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
export type DemoOpLog = {
|
||||||
|
id: number,
|
||||||
|
name: string,
|
||||||
|
optm: string,
|
||||||
|
op: string,
|
||||||
|
userName: string,
|
||||||
|
cmd: string
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type OpLogListItem = {
|
||||||
|
id: number,
|
||||||
|
username: string,
|
||||||
|
userid: number,
|
||||||
|
tm: number;
|
||||||
|
cmd: string;
|
||||||
|
ip: string;
|
||||||
|
gateName: string;
|
||||||
|
eqpno: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DemoStatus = {
|
||||||
|
id: number,
|
||||||
|
name: string,
|
||||||
|
qd: string,
|
||||||
|
s1: number;
|
||||||
|
s2: number;
|
||||||
|
s3: number;
|
||||||
|
s4: number;
|
||||||
|
s5: number;
|
||||||
|
s6: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DemoWarn = {
|
||||||
|
id: number,
|
||||||
|
name: string,
|
||||||
|
qd: string,
|
||||||
|
z1: number;
|
||||||
|
z2: number;
|
||||||
|
q: number;
|
||||||
|
optm: string,
|
||||||
|
op: string,
|
||||||
|
warntm: string,
|
||||||
|
warn: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DemoCamera = {
|
||||||
|
regionIndexCode: string;
|
||||||
|
deviceName: string;
|
||||||
|
cameraList: {
|
||||||
|
indexCode: string;
|
||||||
|
channelName: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type SzRealListItem = {
|
||||||
|
gateCode: string;
|
||||||
|
gateName: string;
|
||||||
|
chanName?: string;
|
||||||
|
stcd: string;
|
||||||
|
eqpno: string;
|
||||||
|
z1?: number;
|
||||||
|
|
||||||
|
z2?: number;
|
||||||
|
hq?: number;
|
||||||
|
|
||||||
|
status?: {
|
||||||
|
"eqpno": string,
|
||||||
|
"shut": boolean, //闸门下降中
|
||||||
|
"autoCtrl": boolean,
|
||||||
|
"gtophgt": number, //当前开度
|
||||||
|
"change": boolean,
|
||||||
|
"fault": boolean, //闸门故障
|
||||||
|
"fullOpen": boolean, //闸门全开位置
|
||||||
|
"allowCtrl": boolean,
|
||||||
|
"stcd": string,
|
||||||
|
"fullClose": boolean, //闸门全关位置
|
||||||
|
"lastCmd": string,
|
||||||
|
"tm": string, //上报时间,同时这个时间若超过10分钟,则认定闸门离线,如若闸门故障或者电源故障是true,这个值也是报警时间
|
||||||
|
"power": boolean, //电源故障
|
||||||
|
"boot": boolean, //闸门上升中
|
||||||
|
"signal": boolean,
|
||||||
|
"maxhgt": number,
|
||||||
|
"minhgt": number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type SafetyListItem = {
|
||||||
|
"gateCode": string; //修改接口要用到的stcd
|
||||||
|
"gateName": string;
|
||||||
|
"chanName": string;
|
||||||
|
"maxhgt": number; //上限位
|
||||||
|
"minhgt": number; //下限位
|
||||||
|
eqpno: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
export type LayerName =
|
||||||
|
'BouaLayer' |
|
||||||
|
'RivlLayer' |
|
||||||
|
'TerrainLayer' |
|
||||||
|
'GQLayer' |
|
||||||
|
'ZQLayer' |
|
||||||
|
'SZLayer' |
|
||||||
|
'ControledSZLayer';
|
||||||
|
|
||||||
|
|
||||||
|
export type RecordId = number | string;
|
||||||
|
|
||||||
|
export type LayerVisibleSettings = { [key: string]: boolean | undefined };
|
||||||
|
|
||||||
|
export type HighlightSetting = {
|
||||||
|
[key: string]: RecordId[] | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LayerSettings = {
|
||||||
|
dom?: boolean;
|
||||||
|
highlight?: HighlightSetting;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CameraTarget = {
|
||||||
|
center?: Position,
|
||||||
|
bound?: [Position, Position],
|
||||||
|
zoom?: number,
|
||||||
|
pitch?: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FeatureTipInfo = {
|
||||||
|
text: string;
|
||||||
|
left: number;
|
||||||
|
top: number;
|
||||||
|
}
|
||||||
|
// [{ id, type, data, lgtd, lttd, elev }]
|
||||||
|
/*export type FeaturePopInfo<T = any> = {
|
||||||
|
id: RecordId;
|
||||||
|
type: string;
|
||||||
|
pos: Position;
|
||||||
|
offsetPop?: boolean;
|
||||||
|
data: T;
|
||||||
|
}*/
|
||||||
|
export type FeaturePopInfo<T = any> = {
|
||||||
|
id: RecordId;
|
||||||
|
type: string;
|
||||||
|
data: T;
|
||||||
|
// @ts-ignore
|
||||||
|
lgtd?: number;
|
||||||
|
// @ts-ignore
|
||||||
|
lgtd?: number;
|
||||||
|
elev?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CameraInfo = {
|
||||||
|
pos: Position;
|
||||||
|
heading: number;
|
||||||
|
pitch: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MapCtrlState = {
|
||||||
|
layerVisible: LayerVisibleSettings;
|
||||||
|
layerSetting: LayerSettings;
|
||||||
|
cameraTarget?: CameraTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type InfoDlg = {
|
||||||
|
layerId: string;
|
||||||
|
properties: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type MarkerInfo = {
|
||||||
|
id: string | number;
|
||||||
|
lgtd: number;
|
||||||
|
lttd: number;
|
||||||
|
elev?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RuntimeState = {
|
||||||
|
layerSetting: any;
|
||||||
|
layerSettingLoop: any;
|
||||||
|
mouseCoords?: Position;
|
||||||
|
featureTip?: FeatureTipInfo;
|
||||||
|
featurePops?: FeaturePopInfo[];
|
||||||
|
infoDlg?: InfoDlg,
|
||||||
|
markers?: { [layerName: string]: MarkerInfo[] | undefined; },
|
||||||
|
viewTick?: number,
|
||||||
|
coordsText?: string,
|
||||||
|
isReadObject?:Object,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type ZmCtrlState = {
|
||||||
|
zmobj?: SZObject;
|
||||||
|
zmInfos?: ZMInfo[]; // 各栅门的基础信息 // todo del
|
||||||
|
kdMax?: number; // 最大开度 todo del
|
||||||
|
selectedId?: string; // 选中的闸门
|
||||||
|
runtime?: { [key: string]: ZMRuntime };
|
||||||
|
|
||||||
|
rz1?: number; // 闸前水位
|
||||||
|
rz2?: number; // 渠道水位
|
||||||
|
rz3?: number; // 闸后水位
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,135 @@
|
||||||
|
import { message } from 'antd'
|
||||||
|
import { wait } from '../../utils/common'
|
||||||
|
import { httpget, httppost } from '../../utils/request'
|
||||||
|
import { MenuItem } from '../_'
|
||||||
|
// import { apiPaths } from '../_/apipath'
|
||||||
|
// import apiurl from '../../service/apiurl'
|
||||||
|
import { store } from '../store'
|
||||||
|
// @ts-ignore
|
||||||
|
import cookie from 'react-cookies'
|
||||||
|
|
||||||
|
export type LoginUser = {
|
||||||
|
id: number
|
||||||
|
loginName: string
|
||||||
|
name: string
|
||||||
|
roleList: string[]
|
||||||
|
tokenInfo: {
|
||||||
|
tokenValue: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AuthState = {
|
||||||
|
user: LoginUser | null | -1
|
||||||
|
menu: MenuItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const USER_SESSION_KEY = '__usereinfo__'
|
||||||
|
|
||||||
|
export function removeLoginInfo() {
|
||||||
|
let keysToKeep = ["checked", "loginNamePwd"];
|
||||||
|
let keysToRemove = [];
|
||||||
|
// 遍历 localStorage
|
||||||
|
for (let i = 0; i < localStorage.length; i++) {
|
||||||
|
let key: any = localStorage.key(i);
|
||||||
|
if (!keysToKeep.includes(key)) {
|
||||||
|
keysToRemove.push(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
for (let i = 0; i < keysToRemove.length; i++) {
|
||||||
|
localStorage.removeItem(keysToRemove[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*localStorage.removeItem(USER_SESSION_KEY);
|
||||||
|
localStorage.removeItem('TOKEN');*/
|
||||||
|
|
||||||
|
// localStorage.clear()
|
||||||
|
sessionStorage.clear()
|
||||||
|
cookie.remove('Admin-Token')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setLoginInfo(userInfo: string, token: string) {
|
||||||
|
sessionStorage.setItem(USER_SESSION_KEY, userInfo)
|
||||||
|
localStorage.setItem('TOKEN', token)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUserFromSession(): LoginUser | null {
|
||||||
|
const strUser = sessionStorage.getItem(USER_SESSION_KEY)
|
||||||
|
if (!strUser) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const obj: LoginUser = JSON.parse(strUser)
|
||||||
|
if (obj.id && obj.tokenInfo.tokenValue) {
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function regByToken(
|
||||||
|
token: string
|
||||||
|
): Promise<LoginUser | undefined> {
|
||||||
|
const result: LoginUser | null = await httppost(
|
||||||
|
// apiPaths.auth.registerByToken,
|
||||||
|
{ token }
|
||||||
|
)
|
||||||
|
if (!result) {
|
||||||
|
message.error('登陆失败')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoginInfo(JSON.stringify(result), result.tokenInfo?.tokenValue)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function idgen() {
|
||||||
|
let id = 1
|
||||||
|
return () => `${id++}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadMenu(): Promise<MenuItem[]> {
|
||||||
|
await wait(200)
|
||||||
|
|
||||||
|
const id = idgen()
|
||||||
|
|
||||||
|
return [
|
||||||
|
{ id: id(), title: '首页', path: '/mgr/home', icon: 'yzt' },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function defaultHomePage() {
|
||||||
|
return '/mgr/home'
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function currentBreadcrumbs() {
|
||||||
|
let url = window.location.href
|
||||||
|
let index = url.lastIndexOf('/')
|
||||||
|
let str = url.substring(index + 1, url.length)
|
||||||
|
let menuData: any = await loadMenu()
|
||||||
|
//console.log("menuData",menuData);
|
||||||
|
let breadcrumbsArray: any = []
|
||||||
|
menuData.map(function (item: any) {
|
||||||
|
if (item.children && item.children.length > 0) {
|
||||||
|
item.children.map(function (item1: any) {
|
||||||
|
if (item1.children && item1.children.length > 0) {
|
||||||
|
item1.children.map(function (item2: any) {
|
||||||
|
let index = item2.path.lastIndexOf('/')
|
||||||
|
if (str === item2.path.substring(index + 1, url.length)) {
|
||||||
|
breadcrumbsArray = [item.title, item1.title, item2.title]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let index = item1.path.lastIndexOf('/')
|
||||||
|
if (str === item1.path.substring(index + 1, url.length)) {
|
||||||
|
breadcrumbsArray = [item.title, item1.title]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return breadcrumbsArray
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { createModel } from "@rematch/core";
|
||||||
|
import { RootModel } from "..";
|
||||||
|
import { MenuItem } from "../_";
|
||||||
|
import { AuthState, getUserFromSession, loadMenu, LoginUser, regByToken, removeLoginInfo } from "./_";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const auth = createModel<RootModel>()({
|
||||||
|
state: {
|
||||||
|
user: getUserFromSession(),
|
||||||
|
menu: [],
|
||||||
|
} as AuthState,
|
||||||
|
|
||||||
|
reducers: {
|
||||||
|
setUser(state, user: LoginUser): AuthState {
|
||||||
|
return { ...state, user };
|
||||||
|
},
|
||||||
|
|
||||||
|
setMenu(state, menu: MenuItem[]): AuthState {
|
||||||
|
return { ...state, menu };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
effects: {
|
||||||
|
async regByToken(token: string): Promise<boolean> {
|
||||||
|
const result = await regByToken(token);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
this.setUser(result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setUser(-1);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
removeLoginInfo();
|
||||||
|
this.setUser(null);
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadMenu() {
|
||||||
|
const data = await loadMenu();
|
||||||
|
this.setMenu(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { MenuItem } from "../_";
|
||||||
|
|
||||||
|
export function findMenu(menus: MenuItem[], pathname: string) {
|
||||||
|
|
||||||
|
if (!menus) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const m1 of menus) {
|
||||||
|
if (m1.path === pathname) {
|
||||||
|
return [m1.id];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m1.children && m1.children.length) {
|
||||||
|
for (const m2 of m1.children) {
|
||||||
|
if (m2.path === pathname) {
|
||||||
|
return [m1.id, m2.id];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m2.children && m2.children.length) {
|
||||||
|
for (const m3 of m2.children) {
|
||||||
|
if (m3.path === pathname) {
|
||||||
|
return [m1.id, m2.id, m3.id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { Models } from "@rematch/core"
|
||||||
|
import { auth } from "./auth";
|
||||||
|
|
||||||
|
export interface RootModel extends Models<RootModel> {
|
||||||
|
auth: typeof auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const models: RootModel = {
|
||||||
|
auth,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { init, RematchDispatch, RematchRootState } from '@rematch/core'
|
||||||
|
import { models, RootModel } from './index'
|
||||||
|
|
||||||
|
export const store = init({
|
||||||
|
models,
|
||||||
|
})
|
||||||
|
|
||||||
|
export type Store = typeof store
|
||||||
|
export type Dispatch = RematchDispatch<RootModel>
|
||||||
|
export type RootState = RematchRootState<RootModel>
|
||||||
|
|
||||||
|
export default store
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
/// <reference types="react-scripts" />
|
||||||
|
declare module '*.module.less' {
|
||||||
|
const classes: { readonly [key: string]: string };
|
||||||
|
export default classes;
|
||||||
|
}
|
||||||
|
declare module '*.less'
|
||||||
|
declare module 'sm-crypto'
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
const service = '/gunshiApp/ss'
|
||||||
|
const apiurl = {
|
||||||
|
login: {
|
||||||
|
login: service + '/login',
|
||||||
|
info: service + '/getInfo',
|
||||||
|
router: service + '/getRouters',
|
||||||
|
role: service + '/system/menu/list'
|
||||||
|
},
|
||||||
|
//核对完都删了重新组织
|
||||||
|
zrrgl: {
|
||||||
|
page: service + "/resPerson/page",
|
||||||
|
edit: service + "/resPerson/update",
|
||||||
|
delete: service + "/resPerson/del",
|
||||||
|
save:service + "/resPerson/insert",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default apiurl
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export type PageResult<T> = {
|
||||||
|
list: T[];
|
||||||
|
totalRow: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SearchOption = {
|
||||||
|
pageSize?: number;
|
||||||
|
pageNumber?: number;
|
||||||
|
pageNum?: number;
|
||||||
|
search?: { [key: string]: any };
|
||||||
|
sortField?: string;
|
||||||
|
sortOrder?: 'asc' | 'desc';
|
||||||
|
stcd?:string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IdObject = {
|
||||||
|
id: string | number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type modeType = 'add' | 'edit' | 'view';
|
||||||
|
|
||||||
|
export type TreeNode = {
|
||||||
|
id: number;
|
||||||
|
key: React.Key;
|
||||||
|
parentId?: number;
|
||||||
|
parentName?: string;
|
||||||
|
title: string;
|
||||||
|
type?: number;
|
||||||
|
disabled?: boolean;
|
||||||
|
children: TreeNode[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LoginUser = {
|
||||||
|
name: string;
|
||||||
|
token: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FileParam = {
|
||||||
|
id: number;
|
||||||
|
tablename: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 附件类型定义
|
||||||
|
export type Attach = {
|
||||||
|
id?: number;
|
||||||
|
filepath: string;
|
||||||
|
usetype?: number;
|
||||||
|
filename?: string;
|
||||||
|
tablename?: string;
|
||||||
|
tableid?: string;
|
||||||
|
orderNum?: number;
|
||||||
|
filetime?: Date;
|
||||||
|
lng?: number;
|
||||||
|
lat?: number;
|
||||||
|
createById?: number;
|
||||||
|
createBy?: string;
|
||||||
|
createTime?: Date;
|
||||||
|
remark?: string;
|
||||||
|
del?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ProjectLog = {
|
||||||
|
code: string;
|
||||||
|
name: string;
|
||||||
|
status: '筹备阶段' | '已开工' | '已竣工';
|
||||||
|
planStm: Date;
|
||||||
|
planEtm: Date;
|
||||||
|
actualStm: Date;
|
||||||
|
actualEtm: Date;
|
||||||
|
proprietor?: string;
|
||||||
|
operator?: string;
|
||||||
|
level:number;
|
||||||
|
projMgr: string;
|
||||||
|
projMgrName: string;
|
||||||
|
fieldMgr: string;
|
||||||
|
jldw: string;
|
||||||
|
sjdw: string;
|
||||||
|
zbwj: string[];
|
||||||
|
tbwj: string[];
|
||||||
|
zbtzs: string[];
|
||||||
|
contracts: string[];
|
||||||
|
attachments?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type ScheduleProps = {
|
||||||
|
wbs: true,
|
||||||
|
level: '单项工程',
|
||||||
|
status: '未开工' | '已开工' | '已完工',
|
||||||
|
phase: '[C]项目实时阶段',
|
||||||
|
} | {
|
||||||
|
task: true;
|
||||||
|
type: string;
|
||||||
|
schedule: string;
|
||||||
|
calendar: string;
|
||||||
|
org?: string;
|
||||||
|
personel?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type Schedule = {
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
stm1: Date;
|
||||||
|
etm1: Date;
|
||||||
|
stm2?: Date;
|
||||||
|
etm2?: Date;
|
||||||
|
|
||||||
|
progress: number;
|
||||||
|
|
||||||
|
props: ScheduleProps;
|
||||||
|
|
||||||
|
remark?: string;
|
||||||
|
|
||||||
|
_indent: number;
|
||||||
|
|
||||||
|
children?: Schedule[] | undefined; // undefine为task,否则就是wbs
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type WorkFlow = {
|
||||||
|
id?: string;
|
||||||
|
title: string;
|
||||||
|
versions?: string;
|
||||||
|
projectNo?: string;
|
||||||
|
status: string;
|
||||||
|
level: string;
|
||||||
|
categoryId: string;
|
||||||
|
categoryName?: string;
|
||||||
|
fromType: string;
|
||||||
|
workFlowName: string;
|
||||||
|
applyName: string;
|
||||||
|
userName: string;
|
||||||
|
applyDate: Date;
|
||||||
|
workflowId: string;
|
||||||
|
businessId: string;
|
||||||
|
createDate: Date;
|
||||||
|
deptId: string;
|
||||||
|
deptName: string;
|
||||||
|
startTime?: Date;
|
||||||
|
endTime?: Date;
|
||||||
|
del: number;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { httppost, ry_httpget } from "../utils/request"
|
||||||
|
import apiUrl from '../service/apiurl'
|
||||||
|
|
||||||
|
export const login = async (params) => {
|
||||||
|
const res = await httppost(apiUrl.login.login, params)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
export const info = async (params) => {
|
||||||
|
const res = await ry_httpget(apiUrl.login.info, params)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
export const router = async (params) => {
|
||||||
|
const res = await ry_httpget(apiUrl.login.router, params)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
const { createProxyMiddleware } = require('http-proxy-middleware');
|
||||||
|
|
||||||
|
module.exports = function (app) {
|
||||||
|
app.use(
|
||||||
|
'/gunshiApp/ss/',
|
||||||
|
createProxyMiddleware({
|
||||||
|
target: 'http://223.75.53.141:83/',//正式环境
|
||||||
|
changeOrigin: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
export function wait(t?: number, data?: any): Promise<any> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve(data);
|
||||||
|
}, t || 1000);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getBasePath(): string {
|
||||||
|
if (process.env.PUBLIC_URL.startsWith('http')) {
|
||||||
|
return process.env.PUBLIC_URL;
|
||||||
|
} else {
|
||||||
|
return window.location.origin + process.env.PUBLIC_URL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function parseGeoJSONFeature(data: any): any {
|
||||||
|
if (typeof data.lgtd === 'number' && typeof data.lttd === 'number') {
|
||||||
|
return {
|
||||||
|
type: "Feature",
|
||||||
|
properties: data,
|
||||||
|
geometry: {
|
||||||
|
type: "Point",
|
||||||
|
coordinates: [data.lgtd, data.lttd]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else if (data.geometry) {
|
||||||
|
let geometryObj = data.geometry;
|
||||||
|
if (typeof geometryObj === 'string') {
|
||||||
|
try {
|
||||||
|
geometryObj = JSON.parse(geometryObj);
|
||||||
|
} catch (e) {
|
||||||
|
geometryObj = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (geometryObj?.type) {
|
||||||
|
return {
|
||||||
|
type: "Feature",
|
||||||
|
properties: data,
|
||||||
|
geometry: geometryObj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
type: "Feature",
|
||||||
|
properties: data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseGeoJSON(data: any): any {
|
||||||
|
const ret: any = {
|
||||||
|
type: "FeatureCollection",
|
||||||
|
crs: {
|
||||||
|
type: "name",
|
||||||
|
properties: {
|
||||||
|
name: "urn:ogc:def:crs:OGC:1.3:CRS84"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
features: []
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
ret.features = data.map(parseGeoJSONFeature);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,146 @@
|
||||||
|
import * as tools from './tools';
|
||||||
|
import { message } from 'antd';
|
||||||
|
function checkStatus(response) {
|
||||||
|
if (response.status >= 200 && response.status < 300) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
const error = new Error(response.statusText);
|
||||||
|
error.response = response;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getToken() {
|
||||||
|
return localStorage.getItem('access_token');
|
||||||
|
}
|
||||||
|
|
||||||
|
function request(url, options,type) {
|
||||||
|
const opt = { ...options };
|
||||||
|
opt.headers = opt.headers || {};
|
||||||
|
opt.headers.Accept = 'application/json';
|
||||||
|
// opt.credentials = opt.credentials || 'include';
|
||||||
|
return fetch(url, opt)
|
||||||
|
.then(checkStatus)
|
||||||
|
.then(response => type=='blob'?response.blob():response.json())
|
||||||
|
.then(data => ({ data })) // { data: 接口实际返回的数据 }
|
||||||
|
.catch(err => ({ err })); // { err: 错误信息 }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function send(url, options) {
|
||||||
|
try {
|
||||||
|
const res = await request(url, options);
|
||||||
|
|
||||||
|
if (!('data' in res) && 'err' in res) {
|
||||||
|
//message.error(getErrCode(res.err.message));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { code } = res.data;
|
||||||
|
if (code === 401) {
|
||||||
|
//debugger;
|
||||||
|
// window.location.href = '/mgr/home';// /mgr/home /login
|
||||||
|
// window.location.href = '/xfflood/#/login';
|
||||||
|
window.location.hash = '#/login';
|
||||||
|
}
|
||||||
|
return res.data;
|
||||||
|
} catch (e) {
|
||||||
|
//message.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function httpget(url, data = {}) {
|
||||||
|
const params = [];
|
||||||
|
for (const k in data) {
|
||||||
|
const v = data[k];
|
||||||
|
if (tools.strIsEmpty(v)) { continue; }
|
||||||
|
|
||||||
|
params.push(`${encodeURIComponent(k)}=${encodeURIComponent(v)}`);
|
||||||
|
}
|
||||||
|
const strparams = params.join('&');
|
||||||
|
if (params.length > 0) {
|
||||||
|
if (url.indexOf('?') > 0) {
|
||||||
|
url += `&${strparams}`;
|
||||||
|
} else {
|
||||||
|
url += `?${strparams}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const options = {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
"gs-token": localStorage.getItem('access_token'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return send(url, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
//若依get请求
|
||||||
|
export function ry_httpget(url, data = {}) {
|
||||||
|
const params = [];
|
||||||
|
for (const k in data) {
|
||||||
|
const v = data[k];
|
||||||
|
if (tools.strIsEmpty(v)) { continue; }
|
||||||
|
|
||||||
|
params.push(`${encodeURIComponent(k)}=${encodeURIComponent(v)}`);
|
||||||
|
}
|
||||||
|
const strparams = params.join('&');
|
||||||
|
if (params.length > 0) {
|
||||||
|
if (url.indexOf('?') > 0) {
|
||||||
|
url += `&${strparams}`;
|
||||||
|
} else {
|
||||||
|
url += `?${strparams}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const options = {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
"cookie":'Token=' + localStorage.getItem('access_token'),
|
||||||
|
"authorization":"Bearer" + ' ' + localStorage.getItem('access_token')
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return send(url, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function httppost(url, data = {}) {
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
"gs-token": localStorage.getItem('access_token'),
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
};
|
||||||
|
|
||||||
|
return send(url, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function httpPostFile(url, data = {}) {
|
||||||
|
const form = new FormData();
|
||||||
|
for (const k in data) {
|
||||||
|
const v = data[k];
|
||||||
|
if (tools.strIsEmpty(v)) { continue; }
|
||||||
|
form.append(k, data[k]);
|
||||||
|
console.log(k,data[k])
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = getToken();
|
||||||
|
if (token) {
|
||||||
|
form.append('token', token);
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
// 'Content-Type': 'multipart/form-data',
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: form,
|
||||||
|
};
|
||||||
|
return send(url, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,583 @@
|
||||||
|
import moment from 'moment';
|
||||||
|
import centerOfMass from '@turf/center-of-mass';
|
||||||
|
import bbox from '@turf/bbox';
|
||||||
|
import turfLength from '@turf/length';
|
||||||
|
import along from '@turf/along';
|
||||||
|
|
||||||
|
const class2type = {};
|
||||||
|
const { toString } = class2type;
|
||||||
|
'Boolean Number String Function Array Date RegExp Object Error'.split(' ').forEach((name) => {
|
||||||
|
class2type[`[object ${name}]`] = name.toLowerCase();
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* 对象类型
|
||||||
|
* @param {object} obj
|
||||||
|
*/
|
||||||
|
export function objType(obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return `${obj}`;
|
||||||
|
}
|
||||||
|
return typeof obj === 'object' || typeof obj === 'function' ? class2type[toString.call(obj)] || 'object' : typeof obj;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 是否数组
|
||||||
|
* @param {object} obj 需要判断的对象
|
||||||
|
* @return {boolean} 返回 true 或 false
|
||||||
|
*/
|
||||||
|
export function isArray(obj) {
|
||||||
|
return objType(obj) === 'array';
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 将简单结构数据转换成树状结构
|
||||||
|
* @param {object} setting 设置节点的 idKey\pIdKey\children
|
||||||
|
* @param {array} sNodes 数据数组
|
||||||
|
* @return {array} 树状解构数据
|
||||||
|
*/
|
||||||
|
export function transformToTreeFormat(setting, sNodes) {
|
||||||
|
setting = setting || {};
|
||||||
|
let i;
|
||||||
|
let l;
|
||||||
|
const key = setting.idKey || 'id'; // 当前节点的唯一key名
|
||||||
|
const parentKey = setting.pIdKey || 'pid'; // 指向的父节点唯一key名
|
||||||
|
const childKey = setting.children || 'children'; // 子元素的key名
|
||||||
|
|
||||||
|
if (!key || key === '' || !sNodes) return [];
|
||||||
|
|
||||||
|
if (isArray(sNodes)) {
|
||||||
|
const r = [];
|
||||||
|
const tmpMap = [];
|
||||||
|
for (i = 0, l = sNodes.length; i < l; i += 1) {
|
||||||
|
tmpMap[sNodes[i][key]] = sNodes[i];
|
||||||
|
}
|
||||||
|
for (i = 0, l = sNodes.length; i < l; i += 1) {
|
||||||
|
if (tmpMap[sNodes[i][parentKey]] && sNodes[i][key] !== sNodes[i][parentKey]) {
|
||||||
|
if (!tmpMap[sNodes[i][parentKey]][childKey]) {
|
||||||
|
tmpMap[sNodes[i][parentKey]][childKey] = [];
|
||||||
|
}
|
||||||
|
tmpMap[sNodes[i][parentKey]][childKey].push(sNodes[i]);
|
||||||
|
} else {
|
||||||
|
r.push(sNodes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [sNodes];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取上级adcd
|
||||||
|
* @param {string} adcd 15位
|
||||||
|
* @return {string} 上级行政区划 adcd 15 位
|
||||||
|
*/
|
||||||
|
export function getAdcdPid(adcd) {
|
||||||
|
if (!adcd || adcd.length !== 15) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adcd === '429021000000000') { // 神农架
|
||||||
|
return '429021000000000';
|
||||||
|
} else if (adcd === '420821450000000') { // 屈家岭
|
||||||
|
return '420800000000000'; // 荆门
|
||||||
|
} else if (adcd === '420381450000000') { // 武当山
|
||||||
|
return '420300000000000'; // 十堰
|
||||||
|
} else if (/00000000000$/.test(adcd)) { // 市
|
||||||
|
return '420000000000000';
|
||||||
|
} else if (/000000000$/.test(adcd)) { // 县\区\县级市
|
||||||
|
return `${adcd.substring(0, 4)}00000000000`;
|
||||||
|
} else if (/000000$/.test(adcd)) { // 乡\镇
|
||||||
|
return `${adcd.substring(0, 6)}000000000`;
|
||||||
|
} else if (/000$/.test(adcd)) { // 行政村
|
||||||
|
return `${adcd.substring(0, 9)}000000`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${adcd.substring(0, 12)}000`; // 自然村
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 根据行政区划设定放缩至的级别
|
||||||
|
* @param {string} adcd 行政区划
|
||||||
|
*/
|
||||||
|
export function getAdcdZoom(adcd) {
|
||||||
|
if (!adcd || adcd.length !== 15) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adcd === '420821450000000') { // 屈家岭
|
||||||
|
return 3;
|
||||||
|
} else if (adcd === '420381450000000') { // 武当山
|
||||||
|
return 3;
|
||||||
|
} else if (/00000000000$/.test(adcd)) { // 市
|
||||||
|
return 2;
|
||||||
|
} else if (/000000000$/.test(adcd)) { // 县\区\县级市
|
||||||
|
return 3;
|
||||||
|
} else if (/000000$/.test(adcd)) { // 乡\镇
|
||||||
|
return 4;
|
||||||
|
} else if (/000$/.test(adcd)) { // 行政村
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 6; // 自然村
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* int 属性值排序
|
||||||
|
* @param {object} o1
|
||||||
|
* @param {object} o2
|
||||||
|
* @param {string} key
|
||||||
|
*/
|
||||||
|
export function orderByInt(o1, o2, key) {
|
||||||
|
const v1 = o1[key] || 0;
|
||||||
|
const v2 = o2[key] || 0;
|
||||||
|
|
||||||
|
if (parseInt(v1, 10) >= parseInt(v2, 10)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 检查用户是否登陆
|
||||||
|
*/
|
||||||
|
export function checkUL() {
|
||||||
|
return true;
|
||||||
|
// const token = cookies.get('token');
|
||||||
|
// const uid = cookies.get('uid');
|
||||||
|
|
||||||
|
// return token != null && uid != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function isEmptyObject(e) {
|
||||||
|
if (e === undefined || e === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (const t in e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function strIsEmpty(v) {
|
||||||
|
// return v === undefined || v == null || v === '';
|
||||||
|
return v === undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function complexUrlParams(resultObj, key, obj) {
|
||||||
|
if (!resultObj) {
|
||||||
|
resultObj = {};
|
||||||
|
}
|
||||||
|
if (typeof obj !== 'object') {
|
||||||
|
resultObj[key] = obj;
|
||||||
|
return resultObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const subkey in obj) {
|
||||||
|
complexUrlParams(resultObj, `${key}[${subkey}]`, obj[subkey]);
|
||||||
|
}
|
||||||
|
return resultObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function arr2map(arrData) {
|
||||||
|
if (!Array.isArray(arrData)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const ret = {};
|
||||||
|
for (const str of arrData) {
|
||||||
|
ret[str] = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function map2arr(mapData) {
|
||||||
|
if (!mapData) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ret = [];
|
||||||
|
for (const key in mapData) {
|
||||||
|
if (mapData[key]) {
|
||||||
|
ret.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isDebug() {
|
||||||
|
return window.location.host.indexOf('dev') > 0 || window.location.host.indexOf('localhost') >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function normalizeSearchTmRange(tm, type) {
|
||||||
|
if (!tm || !tm[0] || !tm[1]) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tm[0] instanceof Date) {
|
||||||
|
tm[0] = moment(tm[0]);
|
||||||
|
}
|
||||||
|
if (tm[1] instanceof Date) {
|
||||||
|
tm[1] = moment(tm[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'd') {
|
||||||
|
return [
|
||||||
|
tm[0].format('YYYY-MM-DD 00:00:00'),
|
||||||
|
tm[1].format('YYYY-MM-DD 00:00:00'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (type === 'm') {
|
||||||
|
return [
|
||||||
|
tm[0].format('YYYY-MM-01 00:00:00'),
|
||||||
|
tm[1].format('YYYY-MM-01 00:00:00'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (type === 't') {
|
||||||
|
return [
|
||||||
|
tm[0].format('YYYY-MM-01 00:00:00'),
|
||||||
|
tm[1].format('YYYY-MM-21 00:00:00'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (type === 'y') {
|
||||||
|
return [
|
||||||
|
tm[0].format('YYYY-01-01 00:00:00'),
|
||||||
|
tm[1].format('YYYY-01-01 00:00:00'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (type === 'h') {
|
||||||
|
return [
|
||||||
|
tm[0].format('YYYY-MM-DD HH:00:00'),
|
||||||
|
tm[1].format('YYYY-MM-DD HH:00:00'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
tm[0].format('YYYY-MM-DD HH:mm:00'),
|
||||||
|
tm[1].format('YYYY-MM-DD HH:mm:00'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeRzMinMax_Dangyang(min, max) {
|
||||||
|
let max50cm = Math.ceil(max * 2);
|
||||||
|
let min50cm = Math.floor(min * 2);
|
||||||
|
let av50cm = Math.ceil(max + min);
|
||||||
|
|
||||||
|
if (av50cm < 3) {
|
||||||
|
av50cm = 3;
|
||||||
|
}
|
||||||
|
if (min50cm < 0) {
|
||||||
|
min50cm = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max50cm < av50cm + 3) {
|
||||||
|
max50cm = av50cm + 3;
|
||||||
|
}
|
||||||
|
if (min50cm > av50cm - 3) {
|
||||||
|
min50cm = av50cm - 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
min: min50cm / 2,
|
||||||
|
max: max50cm / 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MomentTypeFromTmType = {
|
||||||
|
h: 'hour',
|
||||||
|
m: 'month',
|
||||||
|
d: 'day',
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseGeoJSONFeature(data) {
|
||||||
|
if (typeof data.lgtd === 'number' && typeof data.lttd === 'number') {
|
||||||
|
return {
|
||||||
|
type: "Feature",
|
||||||
|
properties: data,
|
||||||
|
geometry: {
|
||||||
|
type: "Point",
|
||||||
|
coordinates: [data.lgtd, data.lttd]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else if (data.geometry) {
|
||||||
|
let geometryObj = data.geometry;
|
||||||
|
if (typeof geometryObj === 'string') {
|
||||||
|
try {
|
||||||
|
geometryObj = JSON.parse(geometryObj);
|
||||||
|
} catch (e) {
|
||||||
|
geometryObj = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (geometryObj?.type) {
|
||||||
|
return {
|
||||||
|
type: "Feature",
|
||||||
|
properties: data,
|
||||||
|
geometry: geometryObj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseGeoJSON(data) {
|
||||||
|
const ret = {
|
||||||
|
type: "FeatureCollection",
|
||||||
|
name: "drpreal",
|
||||||
|
crs: {
|
||||||
|
type: "name",
|
||||||
|
properties: {
|
||||||
|
name: "urn:ogc:def:crs:OGC:1.3:CRS84"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
features: []
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
ret.features = data.map(parseGeoJSONFeature).filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function wait(tm) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve(true);
|
||||||
|
}, tm || 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function strNumber(val, def) {
|
||||||
|
if (typeof val === "number") {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function KrM100Render(val) {
|
||||||
|
if (typeof val !== "number") {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (val * 100).toFixed(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 深度优先遍历树
|
||||||
|
* 一个递归方法
|
||||||
|
* @params tree: 要转换的树结构数据
|
||||||
|
* @params list: 保存结果的列表结构数据,初始传list = []
|
||||||
|
* @params parentId: 当前遍历节点的父级节点id,初始为null(因为根节点无parentId)
|
||||||
|
**/
|
||||||
|
function toListDF(tree, list) {
|
||||||
|
for (let node of tree) { //遍历最上层
|
||||||
|
list.push({
|
||||||
|
id: node.id,
|
||||||
|
key: node.key,
|
||||||
|
title: node.title,
|
||||||
|
type: node?.type,
|
||||||
|
parentId: node?.parentId
|
||||||
|
});
|
||||||
|
//如果有子结点,再遍历子结点
|
||||||
|
if (node.children.length !== 0) {
|
||||||
|
toListDF(node.children, list) //递归
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 树转list
|
||||||
|
*/
|
||||||
|
export function treeToList(tree){
|
||||||
|
const list = []; // 结果list
|
||||||
|
for(let node of tree){
|
||||||
|
if (node?.children?.length !== 0) { //遍历树的第一层,只有一个根结点
|
||||||
|
toListDF(node.children, list); //遍历子树,并加入到list中.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将时间戳转换成年月日
|
||||||
|
*/
|
||||||
|
export function timeChange(val){
|
||||||
|
let time = moment(val).format()
|
||||||
|
|
||||||
|
let d = new Date(time);
|
||||||
|
|
||||||
|
let batchDate = d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate() + ' ' + d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds();
|
||||||
|
|
||||||
|
return batchDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function childNodesDeep(nodes, arr) {
|
||||||
|
if (nodes)
|
||||||
|
nodes.forEach((ele) => {
|
||||||
|
arr.push(ele.key);
|
||||||
|
if (ele.children) {
|
||||||
|
childNodesDeep(ele.children, arr);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取父节点下所有子节点的key
|
||||||
|
* @param nodes
|
||||||
|
* @param key
|
||||||
|
* @param arr
|
||||||
|
* @returns {Array}
|
||||||
|
*/
|
||||||
|
export function getChildKysByParentKey(nodes, key, arr) {
|
||||||
|
for (let el of nodes) {
|
||||||
|
if (el.key === key) {
|
||||||
|
arr.push(el.key);
|
||||||
|
if (el.children) {
|
||||||
|
childNodesDeep(el.children, arr);
|
||||||
|
}
|
||||||
|
} else if (el.children) {
|
||||||
|
getChildKysByParentKey(el.children, key, arr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function geometryCenter(geometry) {
|
||||||
|
if (!geometry) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (typeof geometry === 'string') {
|
||||||
|
geometry = JSON.parse(geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo
|
||||||
|
if (geometry.type === 'MultiLineString') {
|
||||||
|
geometry = {
|
||||||
|
type: 'LineString',
|
||||||
|
coordinates: geometry.coordinates[0]
|
||||||
|
}
|
||||||
|
} else if (geometry.type === 'MultiPolygon') {
|
||||||
|
geometry = {
|
||||||
|
type: 'Polygon',
|
||||||
|
coordinates: geometry.coordinates[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ptgeom = null;
|
||||||
|
if (geometry.type === 'Polygon') {
|
||||||
|
ptgeom = centerOfMass(geometry);
|
||||||
|
} else if (geometry.type === 'LineString') {
|
||||||
|
const length = turfLength(geometry);
|
||||||
|
ptgeom = along(geometry, length * 0.5);
|
||||||
|
}
|
||||||
|
return ptgeom?.geometry?.coordinates;
|
||||||
|
} catch (e) { return null; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function geometryBound(geometry) {
|
||||||
|
if (!geometry) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (typeof geometry === 'string') {
|
||||||
|
geometry = JSON.parse(geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = bbox(geometry);
|
||||||
|
return result;
|
||||||
|
} catch (e) { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const dealValue = (data = [])=>{
|
||||||
|
let linshiObj = {}
|
||||||
|
data?.forEach((item)=>{
|
||||||
|
linshiObj[item.value]=item.label
|
||||||
|
})
|
||||||
|
return linshiObj
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ArrToObj = (data = [])=>{
|
||||||
|
let linshiObj = {}
|
||||||
|
data?.forEach((item)=>{
|
||||||
|
linshiObj[item.value]=item.label
|
||||||
|
})
|
||||||
|
return linshiObj
|
||||||
|
}
|
||||||
|
|
||||||
|
//前端筛选
|
||||||
|
export const myFiltrate = (data,params)=>{
|
||||||
|
const {bgTm,endTm,code,dataSource,ly} = params
|
||||||
|
const myBgTm = moment(bgTm).format('YYYY-MM-DD')+" 00:00:00"
|
||||||
|
const myEndTm = moment(endTm).format('YYYY-MM-DD')+" 23:59:59"
|
||||||
|
const newData = []
|
||||||
|
data?.map((item,index)=>{
|
||||||
|
let flag = 0
|
||||||
|
if(bgTm){
|
||||||
|
if(item?.tm && moment(bgTm).isBefore(item.tm)&&moment(item.tm).isBefore(myEndTm)){
|
||||||
|
}else{
|
||||||
|
flag = flag+1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(code){
|
||||||
|
const str = (item.stnm?item.stnm:"")+(item.stcd?item.stcd:"")+(item.wscd?item.wscd:"")
|
||||||
|
if(str.indexOf(code)>(-1)){
|
||||||
|
}else{
|
||||||
|
flag = flag+1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(dataSource){
|
||||||
|
if(item?.type&&item?.type===dataSource){
|
||||||
|
}else{
|
||||||
|
flag = flag+1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ly){
|
||||||
|
if(item?.wscd&&item?.wscd.indexOf(ly)>0){
|
||||||
|
}else{
|
||||||
|
flag = flag+1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(flag === 0){
|
||||||
|
newData.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return newData
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GetInterval=(min,max,step=10)=>{
|
||||||
|
const distance = Math.ceil(max) - Math.floor(min)
|
||||||
|
console.log(distance);
|
||||||
|
let s = (distance / step);
|
||||||
|
console.log(s);
|
||||||
|
if (s > 5){
|
||||||
|
s = Math.ceil(s / 5) *5;
|
||||||
|
return s;
|
||||||
|
}else{
|
||||||
|
return Math.ceil(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//获取url里key
|
||||||
|
export function getParameter(param) {
|
||||||
|
var query = window.location.hash;
|
||||||
|
var iLen = param.length;
|
||||||
|
var iStart = query.indexOf(param);
|
||||||
|
if (iStart == -1)
|
||||||
|
return "";
|
||||||
|
iStart += iLen + 1;
|
||||||
|
var iEnd = query.indexOf("&", iStart);
|
||||||
|
if (iEnd == -1)
|
||||||
|
return query.substring(iStart);
|
||||||
|
|
||||||
|
return query.substring(iStart, iEnd);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
|
export function changeObjectStringToMoment(obj: { [key: string]: any }, fields: string[]): any {
|
||||||
|
const ret = { ...obj };
|
||||||
|
for (const f of fields) {
|
||||||
|
if (f in ret && typeof ret[f] === 'string') {
|
||||||
|
ret[f] = moment(ret[f]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function apertureMeter(val?: any): number | undefined {
|
||||||
|
if (typeof val !== 'number') {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return val / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renAperture(val?: any) {
|
||||||
|
if (typeof val !== 'number') {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
return (val / 1000).toFixed(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function base64FromFile(file: File): Promise<string | undefined> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
reader.onload = () => {
|
||||||
|
const str = reader.result;
|
||||||
|
if (typeof str === 'string') {
|
||||||
|
resolve(str);
|
||||||
|
}
|
||||||
|
resolve(undefined);
|
||||||
|
}
|
||||||
|
reader.onerror = () => {
|
||||||
|
resolve(undefined);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const normFile = (e: any) => {
|
||||||
|
if (Array.isArray(e)) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
return e?.fileList;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export function randNum(a: number, b: number) {
|
||||||
|
const ret = a * Math.random() + b;
|
||||||
|
return parseFloat(ret.toFixed(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getParameter(param: string) {
|
||||||
|
var query = window.location.hash;
|
||||||
|
var iLen = param.length;
|
||||||
|
var iStart = query.indexOf(param);
|
||||||
|
if (iStart == -1)
|
||||||
|
return "";
|
||||||
|
iStart += iLen + 1;
|
||||||
|
var iEnd = query.indexOf("&", iStart);
|
||||||
|
if (iEnd == -1)
|
||||||
|
return query.substring(iStart);
|
||||||
|
|
||||||
|
return query.substring(iStart, iEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toFixed3(val: any) {
|
||||||
|
if (typeof val !== 'number') {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
return val.toFixed(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renTm(val: any) {
|
||||||
|
if (typeof val !== 'number') {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
return moment(val).format('MM-DD HH:mm:ss')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 驼峰命名转下划线命名
|
||||||
|
export const camel2UnderLine = (str: string) => {
|
||||||
|
let newStr: string = str.replace(/[A-Z]/g,($0) => {
|
||||||
|
return "_" + $0.toLocaleLowerCase();
|
||||||
|
});
|
||||||
|
if(newStr.slice(0,1) == "_"){
|
||||||
|
newStr = newStr.slice(1)
|
||||||
|
}
|
||||||
|
return newStr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 验证图片
|
||||||
|
export const isImg = (file: string) => {
|
||||||
|
return /\.(gif|jpg|jpeg|png|GIF|JPEG|JPG|PNG)$/.test(file);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
import React, { lazy, useEffect } from 'react'
|
||||||
|
import { useDispatch } from 'react-redux'
|
||||||
|
import { Navigate, useRoutes } from 'react-router'
|
||||||
|
import { Dispatch } from '../models/store'
|
||||||
|
import LoginPage from './Login/index'
|
||||||
|
const HomePage = lazy(() => import('./Home'))
|
||||||
|
|
||||||
|
const AppRouters: React.FC = () => {
|
||||||
|
const dispatch = useDispatch<Dispatch>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
;(window as any).__dispatch__ = dispatch
|
||||||
|
return () => {
|
||||||
|
delete (window as any).__dispatch__
|
||||||
|
}
|
||||||
|
}, [dispatch])
|
||||||
|
|
||||||
|
let element = useRoutes([
|
||||||
|
{ path: '/', element: <LoginPage /> },
|
||||||
|
{ path: '/home', element: <HomePage /> },
|
||||||
|
])
|
||||||
|
|
||||||
|
return element
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AppRouters
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
import React from 'react';
|
||||||
|
import CommonCard from '../../UI/CommonCard';
|
||||||
|
import YearSelect from '../../UI/YearSelect';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
const SiGuan = () => {
|
||||||
|
return (
|
||||||
|
<div className="siguan-view">
|
||||||
|
<div className="side-panel left">
|
||||||
|
<CommonCard title="安全鉴定" className="panel-card card-1" >
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
<CommonCard title="库区巡查" className="panel-card card-2" style={{minHeight:120}}>
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
<CommonCard title="闸门监控" className="panel-card card-3">
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
<CommonCard
|
||||||
|
title="安全隐患"
|
||||||
|
className="panel-card card-1"
|
||||||
|
headerExtra={<YearSelect />}
|
||||||
|
>
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="side-panel right">
|
||||||
|
<CommonCard title="水库划界" className="panel-card card-1">
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
<CommonCard title="白蚁防治" className="panel-card card-2">
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
<CommonCard title="维修养护" className="panel-card card-3">
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SiGuan;
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
.siguan-view {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.side-panel {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
width: 25%;
|
||||||
|
min-width: 300px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 10;
|
||||||
|
transition: all 0.3s;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
&.left {
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.right {
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> * {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-card {
|
||||||
|
flex: 1;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder-content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
color: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
import React from 'react';
|
||||||
|
import CommonCard from '../../UI/CommonCard';
|
||||||
|
import ThreeDots from '../../UI/ThreeDots';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
|
||||||
|
const LeftPart = () => {
|
||||||
|
return (
|
||||||
|
<div className="left-part">
|
||||||
|
<CommonCard title="监管全覆盖" className="panel-card card-1">
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
<CommonCard
|
||||||
|
title="监测全要素"
|
||||||
|
className="panel-card card-2"
|
||||||
|
headerExtra={<ThreeDots onClick={() => console.log('监测全要素 clicked')} />}
|
||||||
|
>
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const RightPart = () => {
|
||||||
|
return (
|
||||||
|
<div className="right-part">
|
||||||
|
<CommonCard
|
||||||
|
title="管控全天候"
|
||||||
|
className="panel-card card-1"
|
||||||
|
headerExtra={<ThreeDots onClick={() => console.log('管控全天候 clicked')} />}
|
||||||
|
>
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
<CommonCard title="管理全周期" className="panel-card card-3">
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const SiQuan = () => {
|
||||||
|
return (
|
||||||
|
<div className="siquan-view">
|
||||||
|
<div className="side-panel left">
|
||||||
|
<LeftPart />
|
||||||
|
</div>
|
||||||
|
<div className="side-panel right">
|
||||||
|
<RightPart />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SiQuan;
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
.siquan-view {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative; // Establish positioning context
|
||||||
|
|
||||||
|
.side-panel {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
width: 25%; // Or use vw
|
||||||
|
min-width: 300px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 10; // Ensure panels are above map
|
||||||
|
transition: all 0.3s;
|
||||||
|
pointer-events: none; // Allow clicks to pass through transparent areas if any
|
||||||
|
|
||||||
|
&.left {
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.right {
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-enable pointer events for the cards themselves
|
||||||
|
> * {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Responsive adjustments
|
||||||
|
@media screen and (max-width: 1366px) {
|
||||||
|
gap: 10px;
|
||||||
|
.side-panel {
|
||||||
|
flex: 0 0 28%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-part, .right-part {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0; // Padding handled by parent or margin in cards
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.panel-card {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-part {
|
||||||
|
.card-1 { flex: 4; }
|
||||||
|
.card-2 { flex: 5; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-part {
|
||||||
|
.card-1 { flex: 4; }
|
||||||
|
.card-2 { flex: 3; }
|
||||||
|
.card-3 { flex: 3; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder-content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
color: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
import React from 'react';
|
||||||
|
import CommonCard from '../../UI/CommonCard';
|
||||||
|
import ThreeDots from '../../UI/ThreeDots';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
|
||||||
|
const WarningToggles = () => {
|
||||||
|
return (
|
||||||
|
<div className="warning-toggles">
|
||||||
|
<div className="toggle-item active">
|
||||||
|
<span>监测预警</span>
|
||||||
|
<span className="badge">4</span>
|
||||||
|
</div>
|
||||||
|
<div className="toggle-item">
|
||||||
|
<span>预报预警</span>
|
||||||
|
<span className="badge bg-red">2</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const SiYu = () => {
|
||||||
|
return (
|
||||||
|
<div className="siyu-view">
|
||||||
|
<div className="side-panel left">
|
||||||
|
<CommonCard title="预报" className="panel-card card-1">
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
<CommonCard title="预演" className="panel-card card-2">
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="side-panel right">
|
||||||
|
<CommonCard
|
||||||
|
title="预警"
|
||||||
|
className="panel-card card-1"
|
||||||
|
headerExtra={<WarningToggles />}
|
||||||
|
>
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
<CommonCard
|
||||||
|
title="实时水雨情"
|
||||||
|
className="panel-card card-2"
|
||||||
|
headerExtra={<ThreeDots onClick={() => console.log('实时水雨情 clicked')} />}
|
||||||
|
>
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
|
||||||
|
<CommonCard title="预案" className="panel-card card-3">
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SiYu;
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
.siyu-view {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.side-panel {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
width: 25%;
|
||||||
|
min-width: 300px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 10;
|
||||||
|
transition: all 0.3s;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
&.left {
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.right {
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> * {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-card {
|
||||||
|
flex: 1;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder-content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
color: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning Toggles Styles
|
||||||
|
.warning-toggles {
|
||||||
|
display: flex;
|
||||||
|
gap: 15px;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
.toggle-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: rgba(255,255,255,0.7);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: #00ffff;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
display: inline-block;
|
||||||
|
background: #faad14; // Orange for normal warning
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-left: 5px;
|
||||||
|
|
||||||
|
&.bg-red {
|
||||||
|
background: #f5222d; // Red for urgent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import React from 'react';
|
||||||
|
import CommonCard from '../../UI/CommonCard';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
const SiZhi = () => {
|
||||||
|
return (
|
||||||
|
<div className="sizhi-view">
|
||||||
|
<div className="side-panel left">
|
||||||
|
<CommonCard title="完善体系" className="panel-card card-1">
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
<CommonCard title="健全机制" className="panel-card card-2">
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="side-panel right">
|
||||||
|
<CommonCard title="强化法治" className="panel-card card-1">
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
<CommonCard title="落实责任制" className="panel-card card-2">
|
||||||
|
<div className="placeholder-content">内容填充区域</div>
|
||||||
|
</CommonCard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SiZhi;
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
.sizhi-view {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.side-panel {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
width: 25%;
|
||||||
|
min-width: 300px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 10;
|
||||||
|
transition: all 0.3s;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
&.left {
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.right {
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> * {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-card {
|
||||||
|
flex: 1;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder-content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
color: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import moment from 'moment';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
const Header = ({ activeMenu, onMenuChange }) => {
|
||||||
|
const [time, setTime] = useState(moment());
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
setTime(moment());
|
||||||
|
}, 1000);
|
||||||
|
return () => clearInterval(timer);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const weekMap = {
|
||||||
|
1: '星期一',
|
||||||
|
2: '星期二',
|
||||||
|
3: '星期三',
|
||||||
|
4: '星期四',
|
||||||
|
5: '星期五',
|
||||||
|
6: '星期六',
|
||||||
|
0: '星期日'
|
||||||
|
};
|
||||||
|
|
||||||
|
const menus = [
|
||||||
|
{ key: 'siquan', title: '四全管理' },
|
||||||
|
{ key: 'sizhi', title: '四制体系' },
|
||||||
|
{ key: 'siyu', title: '四预措施' },
|
||||||
|
{ key: 'siguan', title: '四管工作' },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="dashboard-header">
|
||||||
|
<div className="left-area">
|
||||||
|
<div className="time-info">
|
||||||
|
<img src={require('../../../../../assets/images/head/time.png')} alt="time" className="icon" />
|
||||||
|
<span className="time-text">{time.format('YYYY-MM-DD HH:mm:ss')} {weekMap[time.day()]}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="center-area">
|
||||||
|
<div className="menu-group left-menus">
|
||||||
|
{menus.slice(0, 2).map(menu => (
|
||||||
|
<div
|
||||||
|
key={menu.key}
|
||||||
|
className={`menu-item1 ${activeMenu === menu.key ? 'active' : ''}`}
|
||||||
|
onClick={() => onMenuChange(menu.key)}
|
||||||
|
>
|
||||||
|
{menu.title}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="header-title">双石水库现代化运行管理矩阵平台</div>
|
||||||
|
<div className="menu-group right-menus">
|
||||||
|
{menus.slice(2, 4).map(menu => (
|
||||||
|
<div
|
||||||
|
key={menu.key}
|
||||||
|
className={`menu-item2 ${activeMenu === menu.key ? 'active' : ''}`}
|
||||||
|
onClick={() => onMenuChange(menu.key)}
|
||||||
|
>
|
||||||
|
{menu.title}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="right-area">
|
||||||
|
<div className="user-info">
|
||||||
|
<img src={require('../../../../../assets/images/head/user.png')} alt="user" className="icon" />
|
||||||
|
<span className="user-text">当前用户: 系统管理员</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Header;
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
.dashboard-header {
|
||||||
|
width: 100%;
|
||||||
|
height: 80px;
|
||||||
|
background: url('../../../../../assets/images/head/header.png') no-repeat center top;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center; // Center vertically
|
||||||
|
padding: 0 20px; // Horizontal padding
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.left-area, .right-area {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
z-index: 2;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
white-space: nowrap; // Prevent text wrapping
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-area {
|
||||||
|
left: 20px;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-area {
|
||||||
|
right: 20px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-info, .user-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 5px 15px;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-text, .user-text {
|
||||||
|
font-family: 'Arial', sans-serif;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-area {
|
||||||
|
width: 100%; // Take full width
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
margin-top: 10px;
|
||||||
|
|
||||||
|
.header-title {
|
||||||
|
font-size: 32px;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: bold;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
text-shadow: 0 0 10px rgba(0, 200, 255, 0.8);
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin: 0 10vw; // Increased spacing to push menus further outward
|
||||||
|
margin-top: -15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 50px;
|
||||||
|
margin-top: 25px; // Move menus further down
|
||||||
|
|
||||||
|
|
||||||
|
.menu-item1, .menu-item2{
|
||||||
|
width: 180px; // Approx width from image
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
background: url('../../../../../assets/images/head/menu1.png') no-repeat center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
filter: brightness(1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: url('../../../../../assets/images/head/menu2.png') no-repeat center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.menu-item2{
|
||||||
|
background: url('../../../../../assets/images/head/menu3.png') no-repeat center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
&.active {
|
||||||
|
background: url('../../../../../assets/images/head/menu4.png') no-repeat center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import React from 'react';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
const MapContainer = () => {
|
||||||
|
return (
|
||||||
|
<div className="map-container-view">
|
||||||
|
<div className="map-placeholder"></div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MapContainer;
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
.map-container-view {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 0; // Map is the background layer
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background: rgba(0, 0, 0, 0.2); // Keep slight tint or remove
|
||||||
|
|
||||||
|
.map-placeholder {
|
||||||
|
font-size: 24px;
|
||||||
|
color: rgba(0, 160, 233, 0.5);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import React from 'react';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
const CommonCard = ({ title, children, style, className, headerExtra }) => {
|
||||||
|
return (
|
||||||
|
<div className={`common-card ${className || ''}`} style={style}>
|
||||||
|
<div className="card-header">
|
||||||
|
<span className="card-title">{title}</span>
|
||||||
|
{headerExtra && <div className="header-extra">{headerExtra}</div>}
|
||||||
|
</div>
|
||||||
|
<div className="card-content">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CommonCard;
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
.common-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
height: 30px;
|
||||||
|
background: url('../../../../../assets/images/card/header.png') no-repeat left center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between; // Push extra to right
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 10px; // Add right padding
|
||||||
|
margin-bottom:5px;
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: italic;
|
||||||
|
// text-shadow: 0 0 5px #00eaff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-extra {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
flex: 1;
|
||||||
|
background: rgba(0, 0, 0, 0.4); // Fallback or overlay
|
||||||
|
padding: 10px;
|
||||||
|
// min-height: 200px; // Remove fixed min-height to allow custom sizing
|
||||||
|
color: #fff;
|
||||||
|
overflow: hidden; // Prevent overflow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const ThreeDots = ({ onClick, style, className }) => (
|
||||||
|
<div
|
||||||
|
className={className}
|
||||||
|
style={{
|
||||||
|
cursor: 'pointer',
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: '20px',
|
||||||
|
lineHeight: '10px',
|
||||||
|
letterSpacing: '2px',
|
||||||
|
marginRight: '15px',
|
||||||
|
...style
|
||||||
|
}}
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
|
•••
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default ThreeDots;
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Select } from 'antd';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
const { Option } = Select;
|
||||||
|
|
||||||
|
const YearSelect = ({ defaultValue = "2025", style, className, ...props }) => (
|
||||||
|
<Select
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
style={{ width: 80, color: '#fff',marginRight:15,marginTop:5, ...style }}
|
||||||
|
bordered={false}
|
||||||
|
dropdownClassName="year-select-dropdown"
|
||||||
|
className={`year-select ${className || ''}`}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<Option value="2025">2025</Option>
|
||||||
|
<Option value="2024">2024</Option>
|
||||||
|
<Option value="2023">2023</Option>
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default YearSelect;
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
.year-select {
|
||||||
|
color: #fff;
|
||||||
|
.ant-select-selector {
|
||||||
|
color: #fff !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
.ant-select-arrow {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global styles for dropdown (since it renders in body)
|
||||||
|
.year-select-dropdown {
|
||||||
|
background-color: rgba(0, 20, 50, 0.9) !important;
|
||||||
|
border: 1px solid rgba(0, 160, 233, 0.3);
|
||||||
|
|
||||||
|
.ant-select-item {
|
||||||
|
color: #fff;
|
||||||
|
&:hover, &.ant-select-item-option-selected {
|
||||||
|
background-color: rgba(0, 160, 233, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import Header from './components/Layouts/Header';
|
||||||
|
import MapContainer from './components/Map/MapContainer';
|
||||||
|
import SiQuan from './components/Business/SiQuan';
|
||||||
|
import SiZhi from './components/Business/SiZhi';
|
||||||
|
import SiYu from './components/Business/SiYu';
|
||||||
|
import SiGuan from './components/Business/SiGuan';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
const HomePage = () => {
|
||||||
|
const [activeMenu, setActiveMenu] = useState('siquan');
|
||||||
|
|
||||||
|
const renderContent = () => {
|
||||||
|
switch (activeMenu) {
|
||||||
|
case 'siquan':
|
||||||
|
return <SiQuan />;
|
||||||
|
case 'sizhi':
|
||||||
|
return <SiZhi />;
|
||||||
|
case 'siyu':
|
||||||
|
return <SiYu />;
|
||||||
|
case 'siguan':
|
||||||
|
return <SiGuan />;
|
||||||
|
default:
|
||||||
|
return <SiQuan />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="home-page">
|
||||||
|
<Header activeMenu={activeMenu} onMenuChange={setActiveMenu} />
|
||||||
|
<div className="main-content-wrapper">
|
||||||
|
<MapContainer />
|
||||||
|
<div className="content-overlay">
|
||||||
|
{renderContent()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HomePage;
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
.home-page {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background-color: #a2b7cc;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
color: #fff;
|
||||||
|
font-family: "Microsoft YaHei", sans-serif;
|
||||||
|
|
||||||
|
.main-content-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.content-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 5; // Content sits above the map
|
||||||
|
pointer-events: none; // Let clicks pass through to map by default
|
||||||
|
|
||||||
|
// Re-enable pointer events for actual interactive children
|
||||||
|
> * {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.content-layer {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 10; // Above map
|
||||||
|
pointer-events: none; // Let clicks pass through to map by default
|
||||||
|
|
||||||
|
// But children (cards) must be clickable.
|
||||||
|
// This will be handled in child components or we can set it here if all children are full-screen overlays
|
||||||
|
// It's safer to handle in children, but for now, since SiQuan is the child:
|
||||||
|
> * {
|
||||||
|
pointer-events: none;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 494 KiB |
|
After Width: | Height: | Size: 651 KiB |
|
After Width: | Height: | Size: 617 KiB |
|
After Width: | Height: | Size: 2.5 MiB |
|
|
@ -0,0 +1,117 @@
|
||||||
|
.login-root {
|
||||||
|
height: 100vh;
|
||||||
|
background: url(./img/bgTest.png) 0 0 no-repeat;
|
||||||
|
background-size:100% 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: end;
|
||||||
|
|
||||||
|
.login-inner {
|
||||||
|
margin-top: 60px;
|
||||||
|
width: 27%;
|
||||||
|
margin-right: 196px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
display: flex;
|
||||||
|
width: 91%;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
// background-color: rgba(255, 255, 255, .3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loginFormBox{
|
||||||
|
background-color: rgba(255, 255, 255, .5);
|
||||||
|
width: 100%;
|
||||||
|
// height: 60%;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 10px 20px 40px 10px;
|
||||||
|
// margin-bottom: 30px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-top:150px;
|
||||||
|
.loginName{
|
||||||
|
font-family: Adobe Heiti Std;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 25px;
|
||||||
|
color: #01295F;
|
||||||
|
margin: 5% 0 10% 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.ant-form-item-label > label{
|
||||||
|
color:#333;
|
||||||
|
font-size:18px;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
height:35px;
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
.ant-form-item-control-input{
|
||||||
|
width:90%;
|
||||||
|
height: 20%;
|
||||||
|
margin:0 auto;
|
||||||
|
|
||||||
|
.ant-form-item-control-input-content{
|
||||||
|
|
||||||
|
height: 20%;
|
||||||
|
border-radius: 15px;
|
||||||
|
.ant-input-affix-wrapper{
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 15px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.ant-input{
|
||||||
|
// height: 100%;
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-input,.ant-input-affix-wrapper{
|
||||||
|
padding:0 10px;
|
||||||
|
font-size:16px;
|
||||||
|
height:60px;
|
||||||
|
line-height: 38px;
|
||||||
|
background:#fff;
|
||||||
|
|
||||||
|
}
|
||||||
|
.ant-input-affix-wrapper{
|
||||||
|
height:42px;
|
||||||
|
}
|
||||||
|
.ant-btn-primary{
|
||||||
|
width:100%;
|
||||||
|
background:#409EFF;
|
||||||
|
border-color:#409EFF;
|
||||||
|
height:44px;
|
||||||
|
line-height:20px;
|
||||||
|
border-radius:4px;
|
||||||
|
margin-top:10px;
|
||||||
|
}
|
||||||
|
.ant-btn > span{
|
||||||
|
font-size:15px;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-title {
|
||||||
|
font-size: 32px;
|
||||||
|
font-family: Microsoft YaHei;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #307DCC;
|
||||||
|
// background: linear-gradient(to right,#EFF4F8,#EFF4F8,#EFF4F8);
|
||||||
|
background: linear-gradient(to right, #EFF4F8,#A4D6FF,#EFF4F8);
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-input {
|
||||||
|
line-height: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:-webkit-autofill {
|
||||||
|
transition: background-color 5000s ease-in-out 0s;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
-webkit-text-fill-color: #606266; //颜色是设置成你需要的颜色
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
import { Button, Form, Input, message, Checkbox } from 'antd';
|
||||||
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { useNavigate } from 'react-router';
|
||||||
|
import { Dispatch } from '../../models/store';
|
||||||
|
import { UserOutlined, LockOutlined } from '@ant-design/icons';
|
||||||
|
import './index.less';
|
||||||
|
// @ts-ignore
|
||||||
|
import cookie from 'react-cookies'
|
||||||
|
import { login, info } from '../../service/login'
|
||||||
|
|
||||||
|
|
||||||
|
const ReactLazyPreload = (importStatement: any) => {
|
||||||
|
const Component: any = React.lazy(importStatement);
|
||||||
|
Component.preload = importStatement;
|
||||||
|
return Component;
|
||||||
|
};
|
||||||
|
|
||||||
|
// const Home = ReactLazyPreload(() =>
|
||||||
|
// import("../Home")
|
||||||
|
// );
|
||||||
|
|
||||||
|
const LoginPage = () => {
|
||||||
|
const dispatch = useDispatch<Dispatch>();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [checked, setChecked] = useState(false);
|
||||||
|
const formRef = useRef<any>(null)
|
||||||
|
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// Home.preload();
|
||||||
|
// }, []);
|
||||||
|
|
||||||
|
const doLogin = async (value: any) => {
|
||||||
|
const params = {
|
||||||
|
password: value.password,
|
||||||
|
username: value.username
|
||||||
|
}
|
||||||
|
const result = await login(params)
|
||||||
|
if (result.code == 200) {
|
||||||
|
localStorage.setItem('access_token', result.token);
|
||||||
|
cookie.save('Admin-Token', result.token);
|
||||||
|
localStorage.setItem('expires_in', result.token);
|
||||||
|
localStorage.setItem('password', params.password);
|
||||||
|
info().then(res => {
|
||||||
|
getInfo(res,value)
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
message.error((result.description).replace('参数错误',''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const getInfo=(result1:any,value:any)=>{
|
||||||
|
if (result1.code === 200) {
|
||||||
|
if(checked){
|
||||||
|
localStorage.setItem('loginNamePwd',JSON.stringify(value))
|
||||||
|
// localStorage.setItem('checked',checked)
|
||||||
|
}else{
|
||||||
|
localStorage.removeItem('loginNamePwd')
|
||||||
|
}
|
||||||
|
localStorage.setItem('userName', result1.user.nickName);
|
||||||
|
localStorage.setItem('userId', result1.user.userId);
|
||||||
|
navigate('/home');
|
||||||
|
}else{
|
||||||
|
message.error('获取用户信息失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setCheckedChange=(e:any)=>{
|
||||||
|
let ischecked = e.target.checked
|
||||||
|
localStorage.setItem('checked',JSON.stringify(ischecked));
|
||||||
|
setChecked(ischecked)
|
||||||
|
}
|
||||||
|
useEffect(()=>{
|
||||||
|
// localStorage.clear()
|
||||||
|
// sessionStorage.clear()
|
||||||
|
cookie.remove('Admin-Token')
|
||||||
|
let loginNamePwd = localStorage.getItem('loginNamePwd')
|
||||||
|
let cc = localStorage.getItem('checked')
|
||||||
|
let checked = cc && JSON.parse(cc)
|
||||||
|
if(loginNamePwd && formRef.current && checked){
|
||||||
|
formRef.current?.setFieldsValue(JSON.parse(loginNamePwd))
|
||||||
|
setChecked(Boolean(checked))
|
||||||
|
// doLogin(JSON.parse(loginNamePwd))
|
||||||
|
}
|
||||||
|
|
||||||
|
},[])
|
||||||
|
return (
|
||||||
|
<div className='login-root'>
|
||||||
|
<div className='login-inner'>
|
||||||
|
<div className='login-form'>
|
||||||
|
<div style={{ textAlign: 'center', marginBottom: 2 }}>
|
||||||
|
{/* <div className='login-title'>咸丰县防汛调度系统</div> */}
|
||||||
|
</div>
|
||||||
|
<div className="loginFormBox">
|
||||||
|
<div className='loginName'>用户登录</div>
|
||||||
|
<div>
|
||||||
|
<Form
|
||||||
|
name="basic"
|
||||||
|
ref={formRef}
|
||||||
|
initialValues={{ remember: true }}
|
||||||
|
labelCol={{ span: 0 }}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
onFinish={doLogin}
|
||||||
|
autoComplete="off"
|
||||||
|
layout="vertical"
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
name="username"
|
||||||
|
rules={[{ required: true, message: '请输入用户名!' }]}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
prefix={<UserOutlined className="site-form-item-icon" style={{ fontSize: '32px', color: '#3D92FF' }} />}
|
||||||
|
placeholder="请输入账号" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name="password"
|
||||||
|
rules={[{ required: true, message: '请输入密码!' }]}
|
||||||
|
>
|
||||||
|
<Input.Password
|
||||||
|
prefix={<LockOutlined className="site-form-item-icon" style={{ fontSize: '32px', color: '#3D92FF' }} />}
|
||||||
|
placeholder="请输入密码" />
|
||||||
|
</Form.Item>
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'end', margin: '32px' }}>
|
||||||
|
<Checkbox checked={checked} onClick={setCheckedChange}>记住密码</Checkbox>
|
||||||
|
</div>
|
||||||
|
<div style={{ width: '90%', margin: '0 auto' }}>
|
||||||
|
<Button type="primary" style={{borderRadius:25,background:'linear-gradient(to right, #9BC1FF,#1E9DFF)'}} size="large" htmlType="submit" shape="round">
|
||||||
|
登录
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LoginPage
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react-jsx"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||