liujiangyong 1 year ago
parent
commit
9b862eac9a
  1. 146
      api/app/lib/controllers/organization/index.js
  2. 53
      api/app/lib/models/organization.js
  3. 23
      api/app/lib/routes/organization/index.js
  4. BIN
      super-screen/client/assets/images/homepage/water/waterlevelbg.png
  5. 57
      super-screen/client/src/sections/water-prevention/containers/gis.js
  6. 42
      super-screen/client/src/sections/water-prevention/containers/gis.less
  7. 4
      web/client/src/app.js
  8. 6
      web/client/src/sections/organization/actions/index.js
  9. 56
      web/client/src/sections/organization/actions/organization.js
  10. 68
      web/client/src/sections/organization/components/organizationModal.js
  11. 5
      web/client/src/sections/organization/containers/index.js
  12. 195
      web/client/src/sections/organization/containers/organization.js
  13. 5
      web/client/src/sections/organization/containers/style.less
  14. 15
      web/client/src/sections/organization/index.js
  15. 20
      web/client/src/sections/organization/nav-item.js
  16. 5
      web/client/src/sections/organization/reducers/index.js
  17. 12
      web/client/src/sections/organization/routes.js
  18. 6
      web/client/src/utils/webapi.js

146
api/app/lib/controllers/organization/index.js

@ -0,0 +1,146 @@
'use strict';
const Hex = require('crypto-js/enc-hex');
const MD5 = require('crypto-js/md5');
const CryptoJS = require('crypto-js');
function getOrganizationList(opts) {
return async function (ctx, next) {
const models = ctx.fs.dc.models;
const { page, limit, name } = ctx.query;
const Op = ctx.fs.dc.ORM.Op;
let errMsg = { message: '获取机构失败' }
try {
let searchWhere = {
}
let option = {
where: searchWhere,
order: [["id", "desc"]],
attributes: { exclude: ['password'] },
}
if (name) {
searchWhere.name = { $like: '%' + name + '%' };
}
option.where = searchWhere
let limit_ = limit || 10;
let page_ = page || 1;
let offset = (page_ - 1) * limit_;
if (limit && page) {
option.limit = limit_
option.offset = offset
}
const res = await models.Organization.findAndCount(option);
ctx.status = 200;
ctx.body = res;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = errMsg
}
}
}
// 新增机构
function addOrganization(opts) {
return async function (ctx, next) {
const models = ctx.fs.dc.models;
try {
const { name, code } = ctx.request.body
const checkName = await models.Organization.findOne({ where: { name, code } });
if (checkName) {
ctx.status = 400;
ctx.body = { message: "该机构名称&代码组合已存在" }
} else {
let rslt = ctx.request.body;
await models.Organization.create(Object.assign({}, rslt))
ctx.status = 204;
ctx.body = { message: '新建机构成功' }
}
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = { message: '新建机构失败' }
}
}
}
// 修改机构
function editOrganization(opts) {
return async function (ctx, next) {
try {
const models = ctx.fs.dc.models;
const { id } = ctx.params;
const body = ctx.request.body;
const { name, code } = ctx.request.body
const checkName = await models.Organization.findOne({ where: { id: { $not: id }, name, code } });
if (checkName) {
ctx.status = 400;
ctx.body = { message: '该机构名称&代码组合已存在' }
} else {
await models.Organization.update(
body,
{ where: { id: id, } }
)
ctx.status = 204;
ctx.body = { message: '修改机构成功' }
}
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = { message: '修改机构失败' }
}
}
}
// 删除机构
function deleteOrganization(opts) {
return async function (ctx, next) {
try {
const models = ctx.fs.dc.models;
const { id } = ctx.params;
// const checkName1 = await models.MetadataDatabase.findOne({ where: { createBy: id } });
// const checkName2 = await models.MetadataFile.findOne({ where: { createBy: id } });
// const checkName3 = await models.MetadataRestapi.findOne({ where: { createBy: id } });
// if (checkName1 || checkName2 || checkName3) {
// ctx.status = 400;
// ctx.body = { message: '该机构下存在依赖资源无法删除!' }
// } else {
await models.Organization.destroy({
where: {
id: id
}
})
ctx.status = 204;
ctx.body = { message: '删除机构成功' }
// }
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = { message: '删除机构失败' }
}
}
}
module.exports = {
getOrganizationList,
addOrganization,
editOrganization,
deleteOrganization,
}

53
api/app/lib/models/organization.js

@ -0,0 +1,53 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const Organization = sequelize.define("organization", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "organization_id_uindex"
},
name: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "name",
autoIncrement: false
},
code: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "code",
autoIncrement: false
},
ability: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "职能",
primaryKey: false,
field: "ability",
autoIncrement: false
}
}, {
tableName: "organization",
comment: "",
indexes: []
});
dc.models.Organization = Organization;
return Organization;
};

23
api/app/lib/routes/organization/index.js

@ -0,0 +1,23 @@
'use strict';
const organization = require('../../controllers/organization/index');
module.exports = function (app, router, opts, AuthCode) {
app.fs.api.logAttr['POST/organization'] = { content: '增加机构', visible: true };
router.post('/organization', organization.addOrganization(opts))
// 修改机构信息
app.fs.api.logAttr['PUT/organization/:id'] = { content: '修改机构信息', visible: true };
router.put('/organization/:id', organization.editOrganization(opts))
// 删除机构信息
app.fs.api.logAttr['DEL/organization/:id'] = { content: '删除机构信息', visible: true };
router.del('/organization/:id', organization.deleteOrganization(opts))
//获取机构信息列表
app.fs.api.logAttr['GET/organization'] = { content: '获取机构信息列表', visible: true };
router.get('/organization', organization.getOrganizationList(opts));
};

BIN
super-screen/client/assets/images/homepage/water/waterlevelbg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

57
super-screen/client/src/sections/water-prevention/containers/gis.js

@ -34,13 +34,14 @@ function Map(props) {
}); });
map = new AMap.Map(MAPDOMID, { map = new AMap.Map(MAPDOMID, {
center: [116.054664, 28.538966], center: [116.061261, 28.509558],
zoomEnable: true, zoomEnable: true,
dragEnable: true, dragEnable: true,
viewMode: '3D', viewMode: '3D',
pitch: 22.9, pitch: 48.10000000000003,
labelzIndex: 130, labelzIndex: 130,
zoom: 10.3, zoom: 10.75,
rotation: 12.299999999999997,
cursor: 'pointer', cursor: 'pointer',
mapStyle: 'amap://styles/300b147a96946a4f1c1b1b8eb1f92f76', mapStyle: 'amap://styles/300b147a96946a4f1c1b1b8eb1f92f76',
layers: [ layers: [
@ -94,10 +95,10 @@ function Map(props) {
const renderMarkers = () => { const renderMarkers = () => {
map.clearMap(); map.clearMap();
map.setZoom(10.3) // map.setZoom(10.3)
map.setCenter([116.054664, 28.538966]) // map.setCenter([116.054664, 28.538966])
map.setPitch(22.9) // map.setPitch(48.10000000000003)
map.setRotation(1.7000) // map.setRotation(1.7000)
if (loca && heatmap) loca.remove(heatmap) if (loca && heatmap) loca.remove(heatmap)
//初始层级 zoom14以下显示聚合点 //初始层级 zoom14以下显示聚合点
@ -434,8 +435,8 @@ function Map(props) {
gridLayer.setSource(geo); gridLayer.setSource(geo);
gridLayer.setStyle({ gridLayer.setStyle({
unit: 'meter', unit: 'meter',
radius: 600, radius: 400,
gap: 0, gap: 10,
altitude: 100, altitude: 100,
// height: function (index, feature) { // height: function (index, feature) {
// return 6000 // return 6000
@ -449,7 +450,7 @@ function Map(props) {
// return 'red' // return 'red'
// } // }
height: function (index, feature) { height: function (index, feature) {
const baseHeigh = 1400 const baseHeigh = 700
return feature.coordinates[0].properties.x.waterLevel > 30 ? baseHeigh * 14 : return feature.coordinates[0].properties.x.waterLevel > 30 ? baseHeigh * 14 :
feature.coordinates[0].properties.x.waterLevel > 25 ? baseHeigh * 13 : feature.coordinates[0].properties.x.waterLevel > 25 ? baseHeigh * 13 :
feature.coordinates[0].properties.x.waterLevel > 20 ? baseHeigh * 12 : feature.coordinates[0].properties.x.waterLevel > 20 ? baseHeigh * 12 :
@ -501,6 +502,42 @@ function Map(props) {
text.show(); text.show();
text.setText(`${s.waterLevel || '--'}m`) text.setText(`${s.waterLevel || '--'}m`)
text.setPosition(new AMap.LngLat(s.lng, s.lat)); text.setPosition(new AMap.LngLat(s.lng, s.lat));
let infowindow = new AMap.InfoWindow({
isCustom: true, //使用自定义窗体
content: `<div id="water-level" class="water-level-infowindow">
<div style="height:${360}px;" id="contentid${s?.name}"></div></div>`,
offset: new AMap.Pixel(100, 120)
});
text.on('click', () => {
infowindow.open(map, new AMap.LngLat(s.lng, s.lat));
setTimeout(() => {
if (document.getElementById(`contentid${s.name}`)) {
map.setCenter(new AMap.LngLat(s.lng, s.lat))
render(<div>
<div className='gis_exit'
style={{ right: 6, top: 67 }}
onClick={() => {
map.setCenter([115.922069, 28.554867])
map.clearInfoWindow();
}} />
<div className='gis_item'>
<span className='gis_title'>监测站</span>
<span className='gis_text'>{s?.name}</span>
</div>
<div className='gis_item'>
<span className='gis_title'>实时水位</span>
<span className='gis_text'>{`${s.waterLevel || '--'}m`}</span>
</div>
</div>,
document.getElementById(`contentid${s?.name}`));
}
}, 50);
})
}) })

42
super-screen/client/src/sections/water-prevention/containers/gis.less

@ -179,6 +179,48 @@
} }
} }
.water-level-infowindow {
width: 322px;
height: 234.43px;
background: url('/assets/images/homepage/water/waterlevelbg.png') no-repeat;
background-size: 100% 100%;
padding-left: 22px;
padding-top: 140px;
color: #fff;
.gis_exit {
cursor: pointer;
position: absolute;
right: 9px;
top: 42px;
width: 30.75px;
height: 23px;
background: url('/assets/images/homepage/communtity/exit.png') no-repeat;
background-size: 100% 100%;
}
.gis_item {
height: 35px;
background-image: linear-gradient(180deg, #0555a791 0%, #022a6f91 100%);
width: 93%;
display: flex;
align-items: center;
padding-left: 20px;
.gis_title {
font-family: SourceHanSansCN-Regular;
font-weight: 400;
font-size: 14px;
color: #C3E6FF;
letter-spacing: 0;
margin-right: 12px;
}
}
}
.personinfowindow { .personinfowindow {
width: 302px; width: 302px;
height: 420px; height: 420px;

4
web/client/src/app.js

@ -13,6 +13,7 @@ import dataQuality from './sections/dataQuality';
import safetySpecification from './sections/safetySpecification'; import safetySpecification from './sections/safetySpecification';
import backups from './sections/backups'; import backups from './sections/backups';
import dataService from './sections/dataService'; import dataService from './sections/dataService';
import organization from './sections/organization'
const App = props => { const App = props => {
const { projectName } = props const { projectName } = props
@ -34,7 +35,8 @@ const App = props => {
safetySpecification, safetySpecification,
dataService, dataService,
memberManagement, memberManagement,
backups backups,
organization
]} ]}
/> />
) )

6
web/client/src/sections/organization/actions/index.js

@ -0,0 +1,6 @@
'use strict';
import * as member from './organization';
export default {
...member
}

56
web/client/src/sections/organization/actions/organization.js

@ -0,0 +1,56 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getOrganizationList(query) {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
query: query || {},
actionType: 'GET_ORGANIZATION_REPORT',
url: `${ApiTable.getOrganizationList}`,
msg: { error: '获取机构列表失败' },
reducer: { name: 'organization' }
});
}
export function addOrganization(params) {
return (dispatch) => basicAction({
type: 'post',
data: params,
dispatch,
actionType: 'ADD_ORGANIZATION_REPORT',
url: ApiTable.addOrganization,
msg: {
option: '机构新增',
},
});
}
export function deleteOrganization(id) {
return (dispatch) => basicAction({
type: 'del',
dispatch,
actionType: 'DELETE_ORGANIZATION_REPORT',
url: ApiTable.modifyOrganization.replace('{id}', id),
msg: {
option: '机构删除',
},
});
}
export function modifyOrganization(id, params, msg) {
return (dispatch) => basicAction({
type: 'put',
data: params,
dispatch,
actionType: 'MODIFY_ORGANIZATION_REPORT',
url: ApiTable.modifyOrganization.replace('{id}', id),
msg: {
option: msg || '机构编辑',
},
});
}

68
web/client/src/sections/organization/components/organizationModal.js

@ -0,0 +1,68 @@
import React, { useRef } from 'react';
import { Button, Form } from 'antd';
import {
ModalForm,
ProFormText,
} from '@ant-design/pro-form';
export default (props) => {
const { title, triggerRender, editData = null, onFinish, paramsName } = props;
const formItemLayout = { labelCol: { span: 6 }, wrapperCol: { span: 16 } };
const initialValues = editData ? {
...editData,
} : {};
const [form] = Form.useForm();
const formRef = useRef();
return (
<ModalForm
formRef={formRef}
title={title || ''}
initialValues={initialValues}
trigger={
triggerRender ? triggerRender : <Button type="primary" >
{title || ''}
</Button>
}
layout="horizontal"
grid={true}
{...formItemLayout}
modalProps={{
destroyOnClose: true,
onCancel: () => { },
}}
onFinish={async (values) => {
return onFinish && await onFinish(values, editData, form)
// return true;
}}
width={500}
>
<ProFormText
rules={[{ required: true, message: '请输入机构名称' },
{ max: 255, message: '机构名称长度不能大于255个字符' },
]}
name="name"
label="机构名称"
/>
<ProFormText
rules={[{ required: true, message: '请输入机构代码' },
{ max: 255, message: '机构代码长度不能大于255个字符' },
]}
name="code"
label="机构代码"
/>
<ProFormText
rules={[{ required: true, message: '请输入机构职能' },
{ max: 255, message: '机构职能长度不能大于255个字符' },
]}
name="ability"
label="机构职能"
/>
</ModalForm>
);
};

5
web/client/src/sections/organization/containers/index.js

@ -0,0 +1,5 @@
'use strict';
import Organization from './organization';
export { Organization };

195
web/client/src/sections/organization/containers/organization.js

@ -0,0 +1,195 @@
import React, { useEffect, useState } from 'react'
import { Spin, Popconfirm, Select, Row, Col, Button, Input, Table } from 'antd';
import { connect } from 'react-redux';
import ProTable from '@ant-design/pro-table';
import OrganizationModal from '../components/organizationModal';
import { useFsRequest, ApiTable } from '$utils';
import './style.less';
function organization(props) {
const { loading, clientHeight, actions, dispatch, organization, Organization } = props;
const [pageSize, setPageSize] = useState(10);
const [currentPage, setCurrentPage] = useState(1);
const [searchValue, setSearchValue] = useState('')
const [visible, setVisible] = useState(false);//是否展示新增编辑模态框
const [editData, setEditData] = useState(null);//模态框编辑数据
const [refreshTree, setRefreshTree] = useState(1);
const [searchRole, setSearchRole] = useState()
const queryData = (search) => {
const query = {
limit: search ? 10 : pageSize || 10,
page: search ? 1 : currentPage || 1,
name: searchValue,
role: searchRole
}
dispatch(actions.organization.getOrganizationList(query));
}
useEffect(() => {
queryData();
}, [pageSize, currentPage]);
const columns = [
{
title: '序号',
dataIndex: 'index',
render: (text, record, index) => { return index + 1 }
},
{
title: '机构名称',
dataIndex: 'name',
},
{
title: '机构代码',
dataIndex: 'code',
},
{
title: '机构职能',
dataIndex: 'ability',
},
{
title: '操作',
width: 160,
key: 'option',
valueType: 'option',
render: (text, record) => {
const options = [];
options.push(<OrganizationModal
editData={record}
triggerRender={<a>编辑</a>}
title="编辑机构"
onFinish={onFinish}
key="editOrganization"
/>)
options.push(
<Popconfirm
key="del"
placement="top"
title={<><div>是否确认删除该机构</div>
</>}
onConfirm={() => handleDelete(record.id)}
okText="是"
cancelText="否"
>
<a>删除</a>
</Popconfirm>)
return options;
},
},
];
const handleDelete = (id) => {
dispatch(actions.organization.deleteOrganization(id)).then(() => {
queryData();
});
};
const onFinish = async (values, editData) => {
if (editData) {
const dataToSave = { ...values }
return dispatch(
actions.organization.modifyOrganization(editData.id, dataToSave, values?.msg || ''),
).then((res) => {
if (res.success) {
queryData();
return true;
} else {
return false;
}
});
}
return dispatch(actions.organization.addOrganization({
...values,
})).then(res => {
if (res.success) {
queryData();
return true;
} else {
return false;
}
});
};
return <Spin spinning={loading}>
<Row className='protable-title'>
<Col span={12}>
<OrganizationModal
triggerRender={<Button type='primary'>新建</Button>}
title="新建机构"
onFinish={onFinish}
key="addOrganization"
/>
</Col>
<Col span={12} style={{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center' }}>
<span>机构名称 </span> <Input
value={searchValue} onChange={e => { setSearchValue(e.target.value) }}
style={{ width: 220, marginRight: 15 }} placeholder="请输入" />
<Button onClick={() => {
setCurrentPage(1)
setPageSize(10)
queryData(true)
}} type='primary'>查询</Button></Col>
</Row>
<ProTable
columns={columns}
dateFormatter="string"
search={false}
scroll={
{
scrollToFirstRowOnChange: true,
y: clientHeight - 260
}
}
pagination={{
size: 'large',
total: organization?.count,
showSizeChanger: true,
showQuickJumper: true,
current: currentPage,
pageSize: pageSize || 10,
defaultPageSize: 10,
pageSizeOptions: [10, 20, 50],
showTotal: (total) => {
return <span style={{ fontSize: 15 }}>{`${Math.ceil(total / pageSize)}页,${total}`}</span>
},
onShowSizeChange: (currentPage, pageSize) => {
setCurrentPage(currentPage);
setPageSize(pageSize);
},
onChange: (page, pageSize) => {
setCurrentPage(page);
setPageSize(pageSize);
}
}}
dataSource={organization?.rows || []}
options={false}
/>
</Spin>
}
function mapStateToProps(state) {
const {
auth, global, datasources, organization
} = state;
return {
loading: datasources.isRequesting,
clientHeight: global.clientHeight,
actions: global.actions,
organization: organization?.data || {},
};
}
export default connect(mapStateToProps)(organization);

5
web/client/src/sections/organization/containers/style.less

@ -0,0 +1,5 @@
.protable-title {
margin-bottom: 16px;
padding-left: 24px;
padding-right: 24px;
}

15
web/client/src/sections/organization/index.js

@ -0,0 +1,15 @@
'use strict';
import reducers from './reducers';
import routes from './routes';
import actions from './actions';
import { getNavItem } from './nav-item';
export default {
key: 'organization',
name: '机构管理',
reducers: reducers,
routes: routes,
actions: actions,
getNavItem: getNavItem
};

20
web/client/src/sections/organization/nav-item.js

@ -0,0 +1,20 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Menu } from 'antd';
import { UserOutlined } from '@ant-design/icons';
const SubMenu = Menu.SubMenu;
export function getNavItem(user) {
return (
user?.role == '系统管理员' && <Menu.Item icon={<UserOutlined />} key="organization">
<Link to="/organization">机构管理</Link>
</Menu.Item>
// user?.role == '系统管理员' && <SubMenu key="memberManagement" icon={<UserOutlined />} title='用户管理'>
// <Menu.Item key="auth">
// <Link to="/memberManagement/auth">用户权限</Link>
// </Menu.Item>
// </ SubMenu >
)
}

5
web/client/src/sections/organization/reducers/index.js

@ -0,0 +1,5 @@
'use strict';
export default {
}

12
web/client/src/sections/organization/routes.js

@ -0,0 +1,12 @@
'use strict';
import { Organization } from './containers';
export default [{
type: 'inner',
route: {
path: '/organization',
key: 'organization',
breadcrumb: '机构管理',
component: Organization,
}
}];

6
web/client/src/utils/webapi.js

@ -80,11 +80,17 @@ export const ApiTable = {
//资源消费 //资源消费
approveList: 'resource/approve', approveList: 'resource/approve',
//用户管理 //用户管理
getUserList: 'meta/members', getUserList: 'meta/members',
addUser: 'meta/member', addUser: 'meta/member',
modifyUser: 'meta/member/{id}', modifyUser: 'meta/member/{id}',
//机构管理
getOrganizationList: 'organization',
addOrganization: 'organization',
modifyOrganization: 'organization/{id}',
//元数据检索 //元数据检索
searchMetadata: "meta/data/search", searchMetadata: "meta/data/search",

Loading…
Cancel
Save